Archive for September, 2008
Building the Project Euler framework, part 3
In part 2, I showed you an improved, although still pretty basic problem runner framework for Project Euler. I did leave out some things though, and I’m going to try and explain them now.
Firstly, I haven’t really shown how I use the Problem interface. You can see it in part 1 of this series of posts. In Eclipse, you can create a new class in a package, which should bring up the “New Java Class” dialog. Give the class a name - for Project Euler problems I’ve chosen to name them “One”, “Two”, “Three” etc. You can then add an interface that the class is to implement, click ‘Add’, and type in Problem. You can also choose some methods to stub out, tick ‘public static void main(String[] args)’. Click Ok, and you should get something like this:
package co.uk.temporalcohesion.euler.problems; import co.uk.temporalcohesion.euler.interfaces.Problem; public class One implements Problem { public String answer() { // TODO Auto-generated method stub return null; } public int id() { // TODO Auto-generated method stub return 0; } public double time() { // TODO Auto-generated method stub return 0; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub } }
I can hear you asking why am I including then main(String[] args) function if we already have a class that is capable of running the problems (the main Euler class)? Well, what I do to create is to create a Euler object in the problems main method, and get it to run the problem, like this:
/** * @param args */ public static void main(String[] args) { new Euler().run(1, true); }
So the problem class is running itself using the Euler object, which knows how to find the problem, instantiate it and run it. I find doing things this way is easier when working on the problem, as you can simply run the problem as a java application, and it will output the result in a standard format we are expecting to to the console in Eclipse.
Thinking about it, you might be wondering - what’s the point of all this, it seems a little excessive for something that can be done fairly easily? Well - I’ve done it like this because the whole point of me doing the problems on Project Euler, is to practice problem solving and become more comfortable in my use of Java. So I think what I’ve done is pretty valid in that regard.
Building the Project Euler framework, part 2
In Part 1, I showed a basic problem runner framework for Project Euler, however there are a number of ways in which we can improve it. For example:
- How can we run a specific problem?
- How can we hide the answer, but still run the problem?
- How can we avoid manually adding problems to the List of problems?
- Not really to do with the framework, but how can we automate building everything?
I’ll demonstrate some ways that we can do all that, except for the 4th option, which is handled by Ant.
Improving the framework
The first thing that we can do is to add a utility function that handles showing the answers, this way we only have one place in the code that we need to update when we want to change how the answers are shown.
private void showAnswers(Problem problem){ System.out.println("Problem: " + problem.id() + ". Answer: " + problem.answer() + ". Time: " + problem.time() + "s");
}
To run a specific problem, we need to overload the run() function to access the problem we want, and show the answer.
public void run(int i) { try{ Problem problem = (Problem) problems.get(i);/* problem list starts at 0 */ if (problem != null) { showAnswers(problem); } else { System.out.println("There doesn't appear to be an answer for problem " + i); } } catch (IndexOutOfBoundsException e){ System.err.println("There doesn't appear to be an answer for problem " + i); } }
As you can see, we get the specified problem out of the list, and use our new showAnswers() function to display the answer. I’ve tried to include some good error checking - we might try to get a problem that doesn’t exist.
In order to prevent the answer from being shown, we can add a boolean parameter to the run() and showAnswers() functions.
private void showAnswers(Problem problem, boolean showAnswers){ if(showAnswers){ System.out.println("Problem: " + problem.id() + ". Answer: " + problem.answer() + ". Time: " + problem.time() + "s"); } else { problem.answer(); /* we still need to work out the answer */ System.out.println("Problem: " + problem.id() + ". Time: " + problem.time() + "s"); } } public void run(boolean showAnswers) { for (Problem problem : problems) { if (problem != null) { showAnswers(problem, showAnswers); } } }
Dont’t forget to change the overloaded run(int i) to run(int i, boolean showAnswers). This way we can control exactly whether to show the answers when we run all the problems, or to show the answer if we run a specific problem.
One thing remains to do, and that is to correctly parse the command line arguments to control whether the answers are shown or not. We want to handle something like this:
C:\development\euler>java -jar ProjectEuler.jar 42 -noanswer
Where 42 is problem 42, and -noanswer clearly specifies not to show the answer. We’ll also need to handle all combinations of this as well, such as:
C:\development\euler>java -jar ProjectEuler.jar 42
Which should show the answer. I’m not going to show my code for parsing the command line arguements, I’ll leave that as an exercise for the reader, as I believe that it is adequately covered elsewhere on the internet, and in any number of Java books.
The more astute among you will notice that I’ve not mentioned how we are going to avoid manually adding problems to the List of problems. I’ll cover that next time.