Pi Calculator Kata (OOP)

_config.yml

I was cruising code review, looking for an interesting problems and the heavens certainly delivered:

Greg Beech says here that he asks C# candidates to produce a formula that calculates PI Given that Pi can be estimated using the function 4∗(1−1/3+1/5−1/7+…) You can see the answers here:

I went for an OOP approach to solve the problem.

But before I did that, we must answer the question: what should the code look like?

What should good code look like?

Here’s what I think all good code should do:

  1. first and foremost it must be understandable. Most of the code you write will be read many more times than edited. It’s gotta be understandable without having to grok anything.
  2. It must be easy to maintain
  3. and if required must be easy to make changes
  4. Must be testable in some way.
  5. You want to be able to write the thing and get out as soon as you can, while allowing it to be maintainable in the future.

Points about the code:

• API is simpler to read and understand. The main logic is hidden away.

• Easily amenable to change. What if the boss walks in and says he/she wants every 4th fraction to be: 1/e - will your code easily be able to handle that? I’d simply add a new ElementN sub-class called ElementE and add a conditional to my factory method and the changes would be made instantly.

• Employs a polymorphic approach (read: pure OOP) way to handle the problem.

Here is the code

namespace BKTest
{
    public class Pie
    {
        /// <summary>
        /// Estimates pi based on the number of fractions we desire it to estimate by.
        /// The way I view it: you basically have 4 * (element0 + element1 + element2 etc.)
        /// where element0, element1 etc are instances of the Element class.
        /// I use a factory method to instantiate the element types and use polymorphism to differentiate
        /// between the two different types of elements that are currently out there: Element0 and the others: Element1, Element2 etc .
        /// Element zero is different because you can't divide by zero! (This probably won't make any sense)
        /// Till you attempt the problem yourself.
        ///
        /// </summary>
        /// <param name="elementCount"></param>
        /// <returns></returns>
        public double Estimate(int elementCount)
        {
            ElementCollection ec = new ElementCollection(elementCount);
            return 4 * ec.AddAllElements();
        }
    }

    public class ElementCollection
    {
        private int elementCount;

        public ElementCollection(int elementCount)
        {
            this.elementCount = elementCount;
        }

        public double AddAllElements()
        {
            double result = 0.0;
            for (int i = 0; i < elementCount + 1; i++)
            {
                ElementN element = ElementFactory(i);
                result += element.Value();
            }

            return result;
        }

        public ElementN ElementFactory(int i)
        {
            if (i == 0)
            {
                return new Element0(i);
            }
            else
            {
                bool even = (i % 2 == 0);

                if (even)
                {
                    return new ElementEven(i);
                }
                else
                {
                    return new ElementOdd(i);
                }
            }
        }

        public class Element0 : ElementN
        {
            public Element0(int elementCount)
                : base(elementCount)
            {
            }

            public override int Sign()
            {
                return 1;
            }

            public override double PosivitveValue()
            {
                return 1.0;
            }
        }

        public class ElementEven : ElementN
        {
            public ElementEven(int elementCount)
                : base(elementCount)
            {
            }

            public override int Sign()
            {
                return 1;
            }
        }

        public class ElementOdd : ElementN
        {
            public ElementOdd(int elementCount)
                : base(elementCount)
            {
            }

            public override int Sign()
            {
                return -1;
            }
        }

        public abstract class ElementN
        {
            private int elementCount;

            public ElementN(int elementCount)
            {
                this.elementCount = elementCount;
            }

            virtual public double Value()
            {
                return Sign() * PosivitveValue();
            }

            virtual public double PosivitveValue()
            {
                return ((1.0) / (2.0 * elementCount + 1));
            }

            /// <summary>
            /// Either the sign is positive or negative
            /// We could probably put this into its own class
            /// and have a factory method but we'll keep it like this for the moment
            /// till one day change requires us to change it. After all, a sign can only
            /// either be positive or negative. (apparently you can also multiple by the
            /// square root of (-1) but that's another matter.
            /// </summary>
            /// <returns></returns>
            abstract public int Sign();
        }
    }
}

Here are the tests:

using NUnit.Framework;

namespace BKTest
{
    [TestFixture]
    internal class PieTest
    {
        [Test]
        [TestCase(0, 4)]
        [TestCase(1, 4 * (1 - 1.00 / 3.0))]
        [TestCase(2, 4 * (1 - 1.00 / 3.0 + 1 / 5.0))]
        [TestCase(3, 4 * (1 - 1.00 / 3.0 + 1 / 5.0 - 1 / 7.0))]
        [TestCase(4, 4 * (1 - 1.00 / 3.0 + 1 / 5.0 - 1 / 7.0 + 1 / 9.0))]
        public void Estimate_1Parameter_expect_fourMinusOneThird(int input, double output)
        {
            // set up
            double result = new Pie().Estimate(input);
            Assert.AreEqual(output, result);
        }
    }
}
Written on March 28, 2017