Skip to main content
edited tags
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473
Source Link
Denis
  • 8.5k
  • 5
  • 31
  • 76

Project Euler problem solver in windows forms

I've programmed a few Project Euler problem but they are all separated in different solutions so I decided to group them all together in a nice Windows forms application. Here's how it looks like : enter image description here

You can select any of the available problems from the list check the answer and the execution time. I'm looking primarly for code style review or maybe a better way of separating classes and the overall architecture.

Main form class

public partial class Form1 : Form
{
    private readonly Dictionary<string, IProblem> problems = new Dictionary<string, IProblem>();
    private readonly Dictionary<int, ProblemOutput> solvedProblems = new Dictionary<int, ProblemOutput>();

    private IProblem currentProblem;

    public Form1()
    {
        InitializeComponent();
        LoadProblems();
    }

    private void LoadProblems()
    {
        Type[] allProblems = GetDerivedTypesFor(typeof(IProblem)).ToArray();
        foreach (Type problem in allProblems)
        {
            ProblemSelector.Items.Add(FormatName(problem.Name));
            IProblem problemInstance = CreateInstanceByName<IProblem>(problem.Name);
            problems.Add(problem.Name, problemInstance);
        }
    }

    private string FormatName(string inputString)
    {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < inputString.Length; i++)
        {
            if (result.Length > 0)
            {
                if (char.IsUpper(inputString[i]))
                {
                    result.Append(' ');
                }
                else if (i - 1 >= 0 && char.IsNumber(inputString[i]) && char.IsLetter(inputString[i - 1]))
                {
                    result.Append(' ');
                } 
            }
            result.Append(inputString[i]);
        }
        return result.ToString();
    }

    private static T CreateInstanceByName<T>(string className)
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        Type type = assembly.GetTypes().First(t => t.Name == className);
        return (T)Activator.CreateInstance(type);
    }

    private static IEnumerable<Type> GetDerivedTypesFor(Type baseType)
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        return assembly.GetTypes().Where(baseType.IsAssignableFrom).Where(t => baseType != t);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (currentProblem != null)
        {
            ProblemOutput problemOutput;
            if (!solvedProblems.ContainsKey(currentProblem.ID))
            {
                problemOutput = currentProblem.Solve();
                solvedProblems.Add(currentProblem.ID, problemOutput);
            }
            else
            {
                problemOutput = solvedProblems[currentProblem.ID];
            }
            ProblemAnswer.Text = problemOutput.OutputText.ToString();
            ProblemExecutionTime.Text = problemOutput.ExecutionTime/1000d + @" seconds";
        }
    }

    private void ProblemSelector_SelectedIndexChanged(object sender, EventArgs e)
    {
        IProblem selectedProblem = problems[Regex.Replace(((Control)sender).Text, @"\s+", "")];
        if (currentProblem == null || selectedProblem.ID != currentProblem.ID)
        {
            ProblemExecutionTime.Text = string.Empty;
            ProblemAnswer.Text = string.Empty;
            currentProblem = selectedProblem;
            ProblemText.Text = currentProblem.Condition;
        }
    }
}

Base interface for all problems

public interface IProblem
{
    int ID { get; }
    string Condition { get; }
    ProblemOutput Solve();
}

Where ProblemOutput is primarly a wrapper/helper class

public sealed class ProblemOutput
{
    private readonly double executionTime;
    public double ExecutionTime => executionTime;

    private readonly object outputText;
    public object OutputText => outputText;

    public ProblemOutput(double executionTime, object outputText)
    {
        this.executionTime = executionTime;
        this.outputText = outputText;
    }
}

Here's and example of problem class

public sealed class Problem1 : IProblem
{
    public int ID => 1;
    public string Condition => ProblemsConditions.ProblemConditions[ID];

    public ProblemOutput Solve()
    {
        int sum = 0;
        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 1; i < 1000; i++)
        {
            if (i % 3 == 0 || i % 5 == 0)
            {
                sum += i;
            }
        }
        sw.Stop();
        return new ProblemOutput(sw.ElapsedMilliseconds, sum);
    }
}

Any methods shared between at least 2 problems are grouped in the ProblemHelper class

public static class ProblemHelper
{
    private static int GetFactorial(int n)
    {
        int factorial = 1;
        for (int i = 2; i <= n; i++)
        {
            factorial *= i;
        }
        return factorial;
    }

    // some other functions
}