The Assigned Task
Write a program that generates a list of 10,000 numbers in random order each time it is run. Each number in the list must be unique and be between 1 and 10,000 (inclusive).
An explanation of the solution that I've created
I've structured the project as follows:
Doxygen Documentation - Contains Doxygen generated documentation of the codebase. I've only provided the HTML output for the time being. There does seem to be a bug with the way it's parsing the code; I noticed it didn't recognize that ListRandomizer was derived from AbstractRandomizer.
Pandell.RandomApp.CliApplication - Contains the solution for building the command-line interface to the Random application. After building the application, you can go to the \Pandell.RandomApp.CliApplication\Pandell.RandomApp.CliApplication\bin\Debug directory and run Pandell.RandomApp.CliApplication.exe from the command line. If you built it as a Release, it will be in Release directory
Pandell.RandomApp.Common - Contains common classes that are used amongst the different versions of the application (CLI, GUI, and the test driver defined in UnitTests). This isn't a self-standing application, but rather a library of common, shared code.
There are 3 classes defined in this project: AbstractRandomizer, Int32ArrayRandomizer, and ListRandomizer.
AbstractRandomizer is the base class for both Int32ArrayRandomizer and ListRandomizer and defines two abstract methods:
RandomizeInPlace - It takes a container and randomizes the elements in-place Randomize - It takes a container and returns a copy of it, randomized
ListRandomizer takes a List of elements, and Int32ArrayRandomizer takes an array of Int32 elements. I wound up with two different classes because I wanted to see if there was a difference in performance between them. There wasn't.
Essentially, both derived classes of AbstractRandomizer perform the following for their RandomizeInPlace algorithms:
If the container is not null and has more than 1 element Traverse each element in reverse Get a random index value Swap current element with element at random index value
The Randomize methods for both derived classes simply call RandomizeInPlace with a copy of the container, returning the results to the caller.
Pandell.RandomApp.Common.UnitTests - This is *far* from ideal, but I wanted to put together a test driver to run unit tests against the Common library. There are better, less error-prone ways to create unit tests, but I didn't really have time to investigate. If I revisited this, I'd probably look at getting something like NUnit working.
Also, this is far from complete, as it doesn't test every public method for every class defined in the Common library.
Pandell.RandomApp.GuiApplication - Contains the solution for the GUI version of this application. It generates a new set of randomly arranged integers between 1-10000 inclusively and dumps the results in the textbox. You can save the results to a text file through the Save As button.
- The types of numbers that should be used (float or int) wasn't specified, so this version of the application only deals with integers between 1-10000 inclusively. I could always go back and add examples using floats and also use numbers that are not monotonically increasing in value (e.g. 1.001, 2.22, 2.8, 4.56575...), since the ListRandomizer algorithm really doesn't care about the contents of the List itself. The GUI and CLI applications simply create the initial set of data and feed it into the Randomizer.
In a realistic situation, I would request more-clearly defined requirements before coding anything...
- I would probably want to write some test drivers to ensure deep copies are performed for List elements as they get swapped.
- I would probably look at refactoring Int32ArrayRandomizer and ListRandomizer more so that there is less redundancy between the two files. Also, I could have probably defined an interface for this, but didn't really see the point of doing that for this example...
- There are probably more efficient ways to create the array/list of sequential numbers, as well as randomizing it. It would need to be investigated further. However, the interface should not require modification, so the impact would be isolated to the Randomizer classes, rather than the whole application.
- At one point, I had a progress bar that would update during the RandomizeInPlace call. However, it seems that the progress bar would either update way too slowly or way too fast, depending on what I wanted to use as a measure of progress. The update to the progress bar needed to be run on a background thread, so I would see the progress bar lag well after RandomizeInPlace was complete if I decided to base progress on every time 10 numbers were randomized, but if I chose to update the progress bar based on 100 randomized numbers, it would finish too quickly. I decided to leave this out pending further investigation...
- Performance for the GUI application differs greatly between two different machines that I have. This is another action item that I would need to investigate. Also, I've only run this on Windows XP (32 bit), SP3, on a virtual machine. It hasn't been tested with Vista or Win7, in either 32 bit or 64 bit forms.
Also, I coded all of this using Visual Studio 2010 Express Edition, not the full edition of the software...
- Help and About are not yet implemented for the GUI. There is no branding with the GUI.
- I could add support for different input and output formats later on, as well as the ability to let the user specify the input data. Again, this would ideally be defined by end-user requirements...
- I've typically written installers using NSIS, but it would probably be better to investigate using whatever tool Microsoft bundles with Visual Studio. I'm not sure if NSIS can check to see if the correct .Net runtime is installed. I didn't provide an installer for either the CLI or GUI versions of the application. If you need one, let me know and I can make one up fairly quickly.
I think that's it for now. Please let me know if you have any issues cloning the repository; I can email you a .zip file (or tarball) of the project for you to examine. Also, feel free to send my any questions that you might have, or let me know if you run into issues building and running the project.
Just to summarize: The only two projects you should need to open to run the application are either Pandell.RandomApp.GuiApplication (for the GUI version) or Pandell.RandomApp.CliApplication (for the CLI version).
Pandell.RandomApp.Common.UnitTests can also be run on the command-line and was intended for running unit tests only.