diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000000000000000000000000000000000..d1221a932504335fca69084307ab126d2678a3b9
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "contrib/docopt.cpp"]
+	path = contrib/docopt.cpp
+	url = git@github.com:docopt/docopt.cpp.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 64247ab708a12b1afe9dd9b665bdc6695ddf30c0..e649e79d18bbf48ed2439998d9ee2fe6aa9fe581 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,9 +5,10 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
 
 find_package(Boost REQUIRED COMPONENTS iostreams program_options filesystem system serialization)
 include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
-set(libs ${libs} ${Boost_LIBRARIES})
+include_directories(SYSTEM "${PROJECT_SOURCE_DIR}/contrib/docopt.cpp")
+set(libs ${libs} ${Boost_LIBRARIES} docopt_s)
 
-# add_subdirectory("contrib")
+add_subdirectory("contrib/docopt.cpp")
 add_subdirectory("lib")
 add_subdirectory("src")
 
diff --git a/contrib/docopt.cpp b/contrib/docopt.cpp
new file mode 160000
index 0000000000000000000000000000000000000000..ef2ba2a929ae5fd3a7740d15c891bbb7bb1f9b99
--- /dev/null
+++ b/contrib/docopt.cpp
@@ -0,0 +1 @@
+Subproject commit ef2ba2a929ae5fd3a7740d15c891bbb7bb1f9b99
diff --git a/src/generator.cpp b/src/generator.cpp
index 5153a53c76e4cfe42debea3d207ebe1803486149..97d2e2f12b39d1a05e6ed0831fafc5d273f37017 100644
--- a/src/generator.cpp
+++ b/src/generator.cpp
@@ -2,12 +2,27 @@
 #include <reachability.hpp>
 #include <splitting_tree.hpp>
 
+#include <docopt.h>
+
 #include <iostream>
 #include <random>
 #include <fstream>
 
 using namespace std;
 
+static const char USAGE[] =
+    R"(Random Mealy machine generator
+
+    Usage:
+      generator random [-mc] <states> <inputs> <outputs> <machines> [<seed>]
+
+    Options:
+      -h, --help       Show this screen
+      --version        Show version
+      -m, --minimal    Only generate minimal machines
+      -c, --connected  Only generate reachable machines
+)";
+
 static size_t number_of_leaves(splitting_tree const & root) {
 	if (root.children.empty()) return 1;
 
@@ -37,7 +52,8 @@ static mealy generate_random_machine(size_t N, size_t P, size_t Q, mt19937 & gen
 }
 
 static void print_machine(mealy const & m, size_t count) {
-	ofstream file("machine_" + to_string(m.graph_size) + "_" + to_string(m.input_size) + "_" + to_string(m.output_size) + "_" + to_string(count) + ".txt");
+	ofstream file("machine_" + to_string(m.graph_size) + "_" + to_string(m.input_size) + "_"
+	              + to_string(m.output_size) + "_" + to_string(count) + ".txt");
 	for (state s = 0; s < m.graph_size; ++s) {
 		for (input i = 0; i < m.input_size; ++i) {
 			auto e = m.graph[s][i];
@@ -47,44 +63,39 @@ static void print_machine(mealy const & m, size_t count) {
 }
 
 int main(int argc, char * argv[]) {
-	if (argc != 5 && argc != 6) {
-		cerr << "usage: generator <N> <P> <Q> <number of machines> [<seed>]" << endl;
-		return 1;
+	const auto args = docopt::docopt(USAGE, {argv + 1, argv + argc}, true, __DATE__ __TIME__);
+	for (auto const & arg : args) {
+		std::cout << arg.first << arg.second << std::endl;
 	}
 
-	const auto N = stoul(argv[1]);
-	const auto P = stoul(argv[2]);
-	const auto Q = stoul(argv[3]);
-	const auto number_of_machines = stoul(argv[4]);
-
 	auto gen = [&] {
-		if (argc == 6) {
-			auto seed = stoul(argv[5]);
+		if (args.at("<seed>")) {
+			auto seed = args.at("<seed>").asLong();
 			return mt19937(seed);
 		}
 		random_device rd;
 		return mt19937(rd());
 	}();
 
-	size_t count = 0;
-	size_t connected = 0;
-	size_t minimal = 0;
+	size_t number_of_machines = args.at("<machines>").asLong();
+	size_t constructed = 0;
 
-	while (true) {
-		auto const m = generate_random_machine(N, P, Q, gen);
-		auto const m2 = reachable_submachine(m, 0);
-		auto const tree = create_splitting_tree(m2, min_hopcroft_style, 0).root;
+	while (constructed < number_of_machines) {
+		auto const m
+		    = generate_random_machine(args.at("<states>").asLong(), args.at("<inputs>").asLong(),
+		                              args.at("<outputs>").asLong(), gen);
 
-		count++;
-		if (m.graph_size == m2.graph_size) connected++;
-		if (number_of_leaves(tree) == m.graph_size) minimal++;
+		if (args.at("--connected").asBool()) {
+			auto const m2 = reachable_submachine(m, 0);
+			if (m2.graph_size != m.graph_size) continue;
+		}
 
-		if (number_of_leaves(tree) == m.graph_size) {
-			print_machine(m2, minimal);
+		if (args.at("--minimal").asBool()) {
+			auto const tree = create_splitting_tree(m, min_hopcroft_style, 0).root;
+			if (number_of_leaves(tree) != m.graph_size) continue;
 		}
 
-		if (minimal >= number_of_machines) break;
+		constructed++;
+		print_machine(m, constructed);
 	}
-
-	clog << minimal << " / " << connected << " / " << count << endl;
 }