diff --git a/config.json b/config.json index 25fd5401a1..8baee8c64e 100644 --- a/config.json +++ b/config.json @@ -51,7 +51,12 @@ "beer-song", "kindergarten-garden", "pascals-triangle", - "saddle-points" + "saddle-points", + "nth-prime", + "palindrome-products", + "binary-search-tree", + "robot-simulator", + "simple-linked-list" ], "deprecated": [ diff --git a/exercises/binary-search-tree/BinarySearchTreeTest.cs b/exercises/binary-search-tree/BinarySearchTreeTest.cs new file mode 100644 index 0000000000..b7c26fc154 --- /dev/null +++ b/exercises/binary-search-tree/BinarySearchTreeTest.cs @@ -0,0 +1,85 @@ +using System.Linq; +using NUnit.Framework; + +public class BinarySearchTreeTest +{ + [Test] + public void Data_is_retained() + { + var tree = new BinarySearchTree(4); + Assert.That(tree.Value, Is.EqualTo(4)); + } + + [Ignore("Remove to run test")] + [Test] + public void Inserting_less() + { + var tree = new BinarySearchTree(4).Add(2); + Assert.That(tree.Value, Is.EqualTo(4)); + Assert.That(tree.Left.Value, Is.EqualTo(2)); + } + + [Ignore("Remove to run test")] + [Test] + public void Inserting_same() + { + var tree = new BinarySearchTree(4).Add(4); + Assert.That(tree.Value, Is.EqualTo(4)); + Assert.That(tree.Left.Value, Is.EqualTo(4)); + } + + [Ignore("Remove to run test")] + [Test] + public void Inserting_greater() + { + var tree = new BinarySearchTree(4).Add(5); + Assert.That(tree.Value, Is.EqualTo(4)); + Assert.That(tree.Right.Value, Is.EqualTo(5)); + } + + [Ignore("Remove to run test")] + [Test] + public void Complex_tree() + { + var tree = new BinarySearchTree(new [] { 4, 2, 6, 1, 3, 7, 5 }); + Assert.That(tree.Value, Is.EqualTo(4)); + Assert.That(tree.Left.Value, Is.EqualTo(2)); + Assert.That(tree.Left.Left.Value, Is.EqualTo(1)); + Assert.That(tree.Left.Right.Value, Is.EqualTo(3)); + Assert.That(tree.Right.Value, Is.EqualTo(6)); + Assert.That(tree.Right.Left.Value, Is.EqualTo(5)); + Assert.That(tree.Right.Right.Value, Is.EqualTo(7)); + } + + [Ignore("Remove to run test")] + [Test] + public void Iterating_one_element() + { + var elements = new BinarySearchTree(4); + Assert.That(elements, Is.EqualTo(new [] { 4 })); + } + + [Ignore("Remove to run test")] + [Test] + public void Iterating_over_smaller_element() + { + var elements = new BinarySearchTree(new[] { 4, 2 }).AsEnumerable(); + Assert.That(elements, Is.EqualTo(new[] { 2, 4 })); + } + + [Ignore("Remove to run test")] + [Test] + public void Iterating_over_larger_element() + { + var elements = new BinarySearchTree(new[] { 4, 5 }).AsEnumerable(); + Assert.That(elements, Is.EqualTo(new[] { 4, 5 })); + } + + [Ignore("Remove to run test")] + [Test] + public void Iterating_over_complex_element() + { + var elements = new BinarySearchTree(new[] { 4, 2, 1, 3, 6, 7, 5 }).AsEnumerable(); + Assert.That(elements, Is.EqualTo(new[] { 1, 2, 3, 4, 5, 6, 7 })); + } +} \ No newline at end of file diff --git a/exercises/binary-search-tree/Example.cs b/exercises/binary-search-tree/Example.cs new file mode 100644 index 0000000000..6b219a94cd --- /dev/null +++ b/exercises/binary-search-tree/Example.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +public class BinarySearchTree : IEnumerable +{ + public BinarySearchTree(int value) + { + Value = value; + } + + public BinarySearchTree(IEnumerable values) + { + var array = values.ToArray(); + + if (array.Length == 0) + { + throw new ArgumentException("Cannot create tree from empty list"); + } + + Value = array[0]; + + foreach (var value in array.Skip(1)) + { + Add(value); + } + } + + public int Value { get; } + + public BinarySearchTree Left { get; private set; } + + public BinarySearchTree Right { get; private set; } + + public BinarySearchTree Add(int value) + { + if (value <= Value) + { + Left = Add(value, Left); + } + else + { + Right = Add(value, Right); + } + + return this; + } + + private static BinarySearchTree Add(int value, BinarySearchTree tree) + { + if (tree == null) + { + return new BinarySearchTree(value); + } + + return tree.Add(value); + } + + public IEnumerator GetEnumerator() + { + foreach (var left in Left?.AsEnumerable() ?? Enumerable.Empty()) + { + yield return left; + } + + yield return Value; + + foreach (var right in Right?.AsEnumerable() ?? Enumerable.Empty()) + { + yield return right; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/exercises/nth-prime/Example.cs b/exercises/nth-prime/Example.cs new file mode 100644 index 0000000000..75cbe6347f --- /dev/null +++ b/exercises/nth-prime/Example.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +public static class NthPrime +{ + public static int Nth(int nth) + { + return Primes().Skip(nth - 1).First(); + } + + private static IEnumerable Primes() + { + yield return 2; + yield return 3; + + foreach (var prime in PossiblePrimes().Where(IsPrime)) + { + yield return prime; + } + } + + private static IEnumerable PossiblePrimes() + { + var n = 6; + + while (true) + { + yield return n - 1; + yield return n + 1; + + n += 6; + } + } + + private static bool IsPrime(int n) + { + var r = (int)Math.Floor(Math.Sqrt(n)); + + return r < 5 || Enumerable.Range(5, r - 4).All(x => n % x != 0); + } +} \ No newline at end of file diff --git a/exercises/nth-prime/NthPrimeTest.cs b/exercises/nth-prime/NthPrimeTest.cs new file mode 100644 index 0000000000..4e214f1a54 --- /dev/null +++ b/exercises/nth-prime/NthPrimeTest.cs @@ -0,0 +1,20 @@ +using NUnit.Framework; + +public class NthPrimeTest +{ + [TestCase(1, ExpectedResult = 2)] + [TestCase(2, ExpectedResult = 3, Ignore = "Remove to run test case")] + [TestCase(3, ExpectedResult = 5, Ignore = "Remove to run test case")] + [TestCase(4, ExpectedResult = 7, Ignore = "Remove to run test case")] + [TestCase(5, ExpectedResult = 11, Ignore = "Remove to run test case")] + [TestCase(6, ExpectedResult = 13, Ignore = "Remove to run test case")] + [TestCase(7, ExpectedResult = 17, Ignore = "Remove to run test case")] + [TestCase(8, ExpectedResult = 19, Ignore = "Remove to run test case")] + [TestCase(1000, ExpectedResult = 7919, Ignore = "Remove to run test case")] + [TestCase(10000, ExpectedResult = 104729, Ignore = "Remove to run test case")] + [TestCase(10001, ExpectedResult = 104743, Ignore = "Remove to run test case")] + public int Nth_prime_calculated(int nth) + { + return NthPrime.Nth(nth); + } +} \ No newline at end of file diff --git a/exercises/palindrome-products/Example.cs b/exercises/palindrome-products/Example.cs new file mode 100644 index 0000000000..b55b581823 --- /dev/null +++ b/exercises/palindrome-products/Example.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +public class Palindrome +{ + private Palindrome(int value, ISet> factors) + { + Value = value; + Factors = factors; + } + + public int Value { get; } + + public ISet> Factors { get; } + + public static Palindrome Largest(int maxFactor) + { + return Largest(1, maxFactor); + } + + public static Palindrome Largest(int minFactor, int maxFactor) + { + return FindPalindrome(minFactor, maxFactor, x => x.Max(p => p.Item1)); + } + + public static Palindrome Smallest(int maxFactor) + { + return Smallest(1, maxFactor); + } + + public static Palindrome Smallest(int minFactor, int maxFactor) + { + return FindPalindrome(minFactor, maxFactor, x => x.Min(p => p.Item1)); + } + + private static Palindrome FindPalindrome(int minFactor, int maxFactor, Func>>, int> valueSelector) + { + var palindromes = FindAllPalindromes(minFactor, maxFactor); + var value = valueSelector(palindromes); + var factors = new HashSet>(palindromes.Where(p => p.Item1 == value).Select(p => p.Item2)); + + return new Palindrome(value, factors); + } + + private static List>> FindAllPalindromes(int minFactor, int maxFactor) + { + return (from pair in Pairs(minFactor, maxFactor) + let product = pair.Item1 * pair.Item2 + where IsPalindrome(product) + select Tuple.Create(product, pair)) + .ToList(); + } + + private static IEnumerable> Pairs(int minFactor, int maxFactor) + { + return from x in Enumerable.Range(minFactor, maxFactor + 1 - minFactor) + from y in Enumerable.Range(x, maxFactor + 1 - x) + select Tuple.Create(x, y); + } + + private static bool IsPalindrome(int num) + { + var n = num; + var rev = 0; + while (num > 0) + { + var dig = num % 10; + rev = rev * 10 + dig; + num = num / 10; + } + + return n == rev; + } +} diff --git a/exercises/palindrome-products/PalindromeTest.cs b/exercises/palindrome-products/PalindromeTest.cs new file mode 100644 index 0000000000..f7668cf3b6 --- /dev/null +++ b/exercises/palindrome-products/PalindromeTest.cs @@ -0,0 +1,76 @@ +using System; +using NUnit.Framework; + +public class PalindromeTest +{ + [Test] + public void Largest_palindrome_from_single_digit_factors() + { + var actual = Palindrome.Largest(9); + Assert.That(actual.Value, Is.EqualTo(9)); + Assert.That(actual.Factors, Is.EqualTo(new [] { Tuple.Create(1, 9), Tuple.Create(3, 3) })); + } + + [Ignore("Remove to run test")] + [Test] + public void Smallest_palindrome_from_single_digit_factors() + { + var actual = Palindrome.Smallest(9); + Assert.That(actual.Value, Is.EqualTo(1)); + Assert.That(actual.Factors, Is.EqualTo(new[] { Tuple.Create(1, 1) })); + } + + [Ignore("Remove to run test")] + [Test] + public void Largest_palindrome_from_double_digit_actors() + { + var actual = Palindrome.Largest(10, 99); + Assert.That(actual.Value, Is.EqualTo(9009)); + Assert.That(actual.Factors, Is.EqualTo(new[] { Tuple.Create(91, 99) })); + } + + [Ignore("Remove to run test")] + [Test] + public void Smallest_palindrome_from_double_digit_factors() + { + var actual = Palindrome.Smallest(10, 99); + Assert.That(actual.Value, Is.EqualTo(121)); + Assert.That(actual.Factors, Is.EqualTo(new[] { Tuple.Create(11, 11) })); + } + + [Ignore("Remove to run test")] + [Test] + public void Largest_palindrome_from_triple_digit_factors() + { + var actual = Palindrome.Largest(100, 999); + Assert.That(actual.Value, Is.EqualTo(906609)); + Assert.That(actual.Factors, Is.EqualTo(new[] { Tuple.Create(913, 993) })); + } + + [Ignore("Remove to run test")] + [Test] + public void Smallest_palindrome_from_triple_digit_factors() + { + var actual = Palindrome.Smallest(100, 999); + Assert.That(actual.Value, Is.EqualTo(10201)); + Assert.That(actual.Factors, Is.EqualTo(new[] { Tuple.Create(101, 101) })); + } + + [Ignore("Remove to run test")] + [Test] + public void Largest_palindrome_from_four_digit_factors() + { + var actual = Palindrome.Largest(1000, 9999); + Assert.That(actual.Value, Is.EqualTo(99000099)); + Assert.That(actual.Factors, Is.EqualTo(new[] { Tuple.Create(9901, 9999) })); + } + + [Ignore("Remove to run test")] + [Test] + public void Smallest_palindrome_from_four_digit_factors() + { + var actual = Palindrome.Smallest(1000, 9999); + Assert.That(actual.Value, Is.EqualTo(1002001)); + Assert.That(actual.Factors, Is.EqualTo(new[] { Tuple.Create(1001, 1001) })); + } +} \ No newline at end of file diff --git a/exercises/robot-simulator/Example.cs b/exercises/robot-simulator/Example.cs new file mode 100644 index 0000000000..66c4e5e6d7 --- /dev/null +++ b/exercises/robot-simulator/Example.cs @@ -0,0 +1,122 @@ +using System; + +public enum Bearing +{ + North, + East, + South, + West +} + +public struct Coordinate +{ + public Coordinate(int x, int y) + { + X = x; + Y = y; + } + + public int X { get; } + public int Y { get; } +} + +public class RobotSimulator +{ + public RobotSimulator(Bearing bearing, Coordinate coordinate) + { + Bearing = bearing; + Coordinate = coordinate; + } + + public Bearing Bearing { get; private set; } + public Coordinate Coordinate { get; private set; } + + public void TurnRight() + { + switch (Bearing) + { + case Bearing.North: + Bearing = Bearing.East; + break; + case Bearing.East: + Bearing = Bearing.South; + break; + case Bearing.South: + Bearing = Bearing.West; + break; + case Bearing.West: + Bearing = Bearing.North; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + public void TurnLeft() + { + switch (Bearing) + { + case Bearing.North: + Bearing = Bearing.West; + break; + case Bearing.East: + Bearing = Bearing.North; + break; + case Bearing.South: + Bearing = Bearing.East; + break; + case Bearing.West: + Bearing = Bearing.South; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + public void Advance() + { + switch (Bearing) + { + case Bearing.North: + Coordinate = new Coordinate(Coordinate.X, Coordinate.Y + 1); + break; + case Bearing.East: + Coordinate = new Coordinate(Coordinate.X + 1, Coordinate.Y); + break; + case Bearing.South: + Coordinate = new Coordinate(Coordinate.X, Coordinate.Y - 1); + break; + case Bearing.West: + Coordinate = new Coordinate(Coordinate.X - 1, Coordinate.Y); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + public void Simulate(string instructions) + { + foreach (var instruction in instructions) + { + ProcessInstruction(instruction); + } + } + + public void ProcessInstruction(char code) + { + switch (code) + { + case 'L': + TurnLeft(); + break; + case 'R': + TurnRight(); + break; + case 'A': + Advance(); + break; + default: + throw new ArgumentOutOfRangeException("Invalid instruction"); + } + } +} \ No newline at end of file diff --git a/exercises/robot-simulator/RobotSimulatorTest.cs b/exercises/robot-simulator/RobotSimulatorTest.cs new file mode 100644 index 0000000000..ed4d9b807a --- /dev/null +++ b/exercises/robot-simulator/RobotSimulatorTest.cs @@ -0,0 +1,64 @@ +using NUnit.Framework; + +public class RobotSimulatorTest +{ + [Test] + public void Turn_right_edge_case() + { + var robot = new RobotSimulator(Bearing.West, new Coordinate(0, 0)); + robot.TurnRight(); + Assert.That(robot.Bearing, Is.EqualTo(Bearing.North)); + } + + [Ignore("Remove to run test")] + [Test] + public void Turn_left_edge_case() + { + var robot = new RobotSimulator(Bearing.North, new Coordinate(0, 0)); + robot.TurnLeft(); + Assert.That(robot.Bearing, Is.EqualTo(Bearing.West)); + } + + [Ignore("Remove to run test")] + [Test] + public void Robbie() + { + var robbie = new RobotSimulator(Bearing.East, new Coordinate(-2, 1)); + Assert.That(robbie.Bearing, Is.EqualTo(Bearing.East)); + Assert.That(robbie.Coordinate, Is.EqualTo(new Coordinate(-2, 1))); + + robbie.Simulate("RLAALAL"); + Assert.That(robbie.Bearing, Is.EqualTo(Bearing.West)); + Assert.That(robbie.Coordinate, Is.EqualTo(new Coordinate(0, 2))); + } + + [Ignore("Remove to run test")] + [Test] + public void Clutz() + { + var clutz = new RobotSimulator(Bearing.North, new Coordinate(0, 0)); + clutz.Simulate("LAAARALA"); + Assert.That(clutz.Bearing, Is.EqualTo(Bearing.West)); + Assert.That(clutz.Coordinate, Is.EqualTo(new Coordinate(-4, 1))); + } + + [Ignore("Remove to run test")] + [Test] + public void Sphero() + { + var sphero = new RobotSimulator(Bearing.East, new Coordinate(2, -7)); + sphero.Simulate("RRAAAAALA"); + Assert.That(sphero.Bearing, Is.EqualTo(Bearing.South)); + Assert.That(sphero.Coordinate, Is.EqualTo(new Coordinate(-3, -8))); + } + + [Ignore("Remove to run test")] + [Test] + public void Roomba() + { + var roomba = new RobotSimulator(Bearing.South, new Coordinate(8, 4)); + roomba.Simulate("LAAARRRALLLL"); + Assert.That(roomba.Bearing, Is.EqualTo(Bearing.North)); + Assert.That(roomba.Coordinate, Is.EqualTo(new Coordinate(11, 5))); + } +} \ No newline at end of file diff --git a/exercises/simple-linked-list/Example.cs b/exercises/simple-linked-list/Example.cs new file mode 100644 index 0000000000..ac6c7115a6 --- /dev/null +++ b/exercises/simple-linked-list/Example.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +public class SimpleLinkedList : IEnumerable +{ + public SimpleLinkedList(T value) : + this(new[] { value }) + { + } + + public SimpleLinkedList(IEnumerable values) + { + var array = values.ToArray(); + + if (array.Length == 0) + { + throw new ArgumentException("Cannot create tree from empty list"); + } + + Value = array[0]; + Next = null; + + foreach (var value in array.Skip(1)) + { + Add(value); + } + } + + public T Value { get; } + + public SimpleLinkedList Next { get; private set; } + + public SimpleLinkedList Add(T value) + { + var last = this; + + while (last.Next != null) + { + last = last.Next; + } + + last.Next = new SimpleLinkedList(value); + + return this; + } + + public SimpleLinkedList Reverse() + { + return new SimpleLinkedList(this.AsEnumerable().Reverse()); + } + + public IEnumerator GetEnumerator() + { + yield return Value; + + foreach (var next in Next?.AsEnumerable() ?? Enumerable.Empty()) + { + yield return next; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/exercises/simple-linked-list/SimpleLinkedListTest.cs b/exercises/simple-linked-list/SimpleLinkedListTest.cs new file mode 100644 index 0000000000..802fd1d93c --- /dev/null +++ b/exercises/simple-linked-list/SimpleLinkedListTest.cs @@ -0,0 +1,87 @@ +using System.Linq; +using NUnit.Framework; + +public class SimpleLinkedListTest +{ + [Test] + public void Single_item_list_value() + { + var list = new SimpleLinkedList(1); + Assert.That(list.Value, Is.EqualTo(1)); + } + + [Ignore("Remove to run test")] + [Test] + public void Single_item_list_has_no_next_item() + { + var list = new SimpleLinkedList(1); + Assert.That(list.Next, Is.Null); + } + + [Ignore("Remove to run test")] + [Test] + public void Two_item_list_first_value() + { + var list = new SimpleLinkedList(2).Add(1); + Assert.That(list.Value, Is.EqualTo(2)); + } + + [Ignore("Remove to run test")] + [Test] + public void Two_item_list_second_value() + { + var list = new SimpleLinkedList(2).Add(1); + Assert.That(list.Next.Value, Is.EqualTo(1)); + } + + [Ignore("Remove to run test")] + [Test] + public void Two_item_list_second_item_has_no_next() + { + var list = new SimpleLinkedList(2).Add(1); + Assert.That(list.Next.Next, Is.Null); + } + + [Ignore("Remove to run test")] + [Test] + public void Implements_enumerable() + { + var values = new SimpleLinkedList(2).Add(1); + Assert.That(values, Is.EqualTo(new[] { 2, 1 })); + } + + [Ignore("Remove to run test")] + [Test] + public void From_enumerable() + { + var list = new SimpleLinkedList(new[] { 11, 7, 5, 3, 2 }); + Assert.That(list.Value, Is.EqualTo(11)); + Assert.That(list.Next.Value, Is.EqualTo(7)); + Assert.That(list.Next.Next.Value, Is.EqualTo(5)); + Assert.That(list.Next.Next.Next.Value, Is.EqualTo(3)); + Assert.That(list.Next.Next.Next.Next.Value, Is.EqualTo(2)); + } + + [TestCase(1, Ignore = "Remove to run test case")] + [TestCase(2, Ignore = "Remove to run test case")] + [TestCase(10, Ignore = "Remove to run test case")] + [TestCase(100, Ignore = "Remove to run test case")] + public void Reverse(int length) + { + var values = Enumerable.Range(1, length).ToArray(); + var list = new SimpleLinkedList(values); + var reversed = list.Reverse(); + Assert.That(reversed, Is.EqualTo(values.Reverse())); + } + + [TestCase(1, Ignore = "Remove to run test case")] + [TestCase(2, Ignore = "Remove to run test case")] + [TestCase(10, Ignore = "Remove to run test case")] + [TestCase(100, Ignore = "Remove to run test case")] + public void Roundtrip(int length) + { + var values = Enumerable.Range(1, length); + var listValues = new SimpleLinkedList(values); + Assert.That(listValues, Is.EqualTo(values)); + } +} \ No newline at end of file