Monday, October 5, 2009

Project Euler

I realize I've been neglecting this blog for awhile, but I think I finally have something interesting to write about, so I'm going to try keeping this updated again.

After a recent post by Steve Smith, I got started doing some of the Project Euler problems. Like Steve, I've been using this as an opportunity to get more familiar with some of the .NET 2.0/3.5 features that I haven't used much in my daily coding, including Linq, iterators and extension methods.

Over the next few posts, I'll be writing about some of the problems, and posting my solutions to them. I won't post code for every problem, just some of the ones I've found more interesting, or that I came up with a cool solution for.

For today, I will post the class launcher (i.e., the main program). The way I structured things, I created a solution in Visual Studio called ProjectEuler. I then create a class for each problem, called "ProblemNNN" where "NNN" is the problem number. The launcher takes the class name on the command line, then uses reflection to load the class, instantiate an instance of it then run it. It also times the execution and displays the elapsed time at the end. Below is the code for the Launcher class.

using System;
using System.Linq;
using System.Reflection;
using System.Diagnostics;

namespace ProjectEuler
{
public class Launcher
{
public static void Main(string[] args)
{
Assembly myAssembly = Assembly.GetExecutingAssembly();
try
{
if (args.Length != 1)
{
Usage(myAssembly, false);
}

if (args[0] == "/?")
{
Usage(myAssembly, true);
}

Type type = myAssembly.GetType("ProjectEuler." + args[0]);

if (type == null)
{
Console.WriteLine("Class {0} not found\r\n", args[0]);
Usage(myAssembly, true);
return;
}

var obj = Activator.CreateInstance(type);

Console.WriteLine("\nEuler {0}", args[0]);
Console.WriteLine("================\n");

FieldInfo summary = type.GetField("summary");
Console.WriteLine("{0}\r\n", summary.GetValue(obj));

Stopwatch sw = new Stopwatch();
sw.Start();

type.InvokeMember("Run", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, null);

sw.Stop();
Console.WriteLine("\r\nElapsed time: {0} ({1} ms)", sw.Elapsed, sw.ElapsedMilliseconds);

if (Debugger.IsAttached)
{
Console.WriteLine("\nPress return to quit.");
Console.ReadLine();
}
}
catch (Exception ex)
{
if (args.Length > 0)
{
Console.WriteLine("Exception trying to execute method on {0}: {1}\r\n", args[0], ex.Message);
if (ex.InnerException != null)
{
Console.WriteLine(" Inner exception: {0}", ex.InnerException);
}
}
else
{
Console.WriteLine("Exception in problem runner methods: {0}\r\n", ex.Message);
}
Usage(myAssembly, false);
}
}

private static void Usage(Assembly myAssembly, bool showClasses)
{
Console.WriteLine("Usage: ProjectEuler.exe ");

if (showClasses)
{
Console.WriteLine("\r\nPossible classnames:");

myAssembly.GetTypes().Where(t => t.Name.StartsWith("Problem")).OrderBy(t => t.Name).ToList().ForEach(
t => Console.WriteLine(" {0}", t.Name));
}
else
{
Console.Out.WriteLine(" add /? to show list of classes");
}

Environment.Exit(1);
}
}
}

No comments: