diff --git a/.vscode/settings.json b/.vscode/settings.json
index b1e4d84cff55f05867180fbd863db5ecf3f2d593..ed279b2148df6da0d049ea58b9395afba7bdaf70 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -43,6 +43,21 @@
         "ranges": "cpp",
         "fstream": "cpp",
         "algorithm": "cpp",
-        "numeric": "cpp"
+        "numeric": "cpp",
+        "atomic": "cpp",
+        "bit": "cpp",
+        "chrono": "cpp",
+        "condition_variable": "cpp",
+        "cstdarg": "cpp",
+        "cstddef": "cpp",
+        "ctime": "cpp",
+        "iterator": "cpp",
+        "memory": "cpp",
+        "memory_resource": "cpp",
+        "random": "cpp",
+        "ratio": "cpp",
+        "future": "cpp",
+        "mutex": "cpp",
+        "thread": "cpp"
     }
 }
diff --git a/Makefile b/Makefile
index 9de4fc21cc99928c3ec5fa637036c9cc404bfc6d..e6069f3c36a133bd0c37a7e1aaa1fa6996e9ea7e 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ text_ioc: text_ioc.cpp fitness/quadgrams.cpp
 	g++ -g -std=c++17 text_ioc.cpp fitness/quadgrams.cpp -o text_ioc
 
 crack: crack.cpp fitness/quadgrams.cpp
-	g++ -O3 -std=c++17 crack.cpp fitness/quadgrams.cpp -o crack
+	g++ -O3 -std=c++17 crack.cpp fitness/quadgrams.cpp -o crack -lpthread
 
 clean:
 	rm -rf crack text_ioc
diff --git a/crack b/crack
index 2938fa6482c3260fa70bfe08c0692cd3bafb0624..9e65b58c6facf5c2bb380ec1860d92c1140f2897 100755
Binary files a/crack and b/crack differ
diff --git a/crack.cpp b/crack.cpp
index b4eb54feae68d4ee7549b3c0ab1edd1770b25449..a5d59fdb8160674d59d4103008877d9291a34db4 100644
--- a/crack.cpp
+++ b/crack.cpp
@@ -1,6 +1,7 @@
 #include <sstream>
 #include <algorithm>
 #include <vector>
+#include <future>
 
 #include "enigma/enigma.h"
 
@@ -14,7 +15,22 @@ struct Setting
     double score;
 };
 
-Setting try_all_keys(const std::string &firstRotor, const std::string &secondRotor, const std::string &thirdRotor, const std::string &cipher)
+char int_to_char(int c)
+{
+    return static_cast<char>(c + 'A');
+}
+
+std::array<std::string, 8> rotorNames = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII"};
+
+std::ostream &operator<<(std::ostream &s, const Setting &set)
+{
+    s << rotorNames[set.rotorIndexes[0]] << " " << rotorNames[set.rotorIndexes[1]] << " " << rotorNames[set.rotorIndexes[2]];
+    s << " - " << int_to_char(set.rotorPositions[0]) << " " << int_to_char(set.rotorPositions[1]) << " " << int_to_char(set.rotorPositions[2]);
+    // s << " - " << set.text;
+    return s << " : " << set.score;
+}
+
+Setting try_all_keys(int firstRotor, int secondRotor, int thirdRotor, const std::string &cipher)
 {
     std::vector<std::string> pairs;
     for (size_t i = 0; i < 10; i++)
@@ -29,6 +45,7 @@ Setting try_all_keys(const std::string &firstRotor, const std::string &secondRot
     best.score = -999999999999999999;
     best.rotorPositions = {0, 0, 0};
     best.text = "";
+    best.rotorIndexes = {firstRotor, secondRotor, thirdRotor};
 
     for (int i = 0; i < 26; i++)
     {
@@ -36,9 +53,9 @@ Setting try_all_keys(const std::string &firstRotor, const std::string &secondRot
         {
             for (int k = 0; k < 26; k++)
             {
-                Rotor left_rotor = rotors.at(firstRotor).Duplicate(0, i);
-                Rotor center_rotor = rotors.at(secondRotor).Duplicate(0, j);
-                Rotor right_rotor = rotors.at(thirdRotor).Duplicate(0, k);
+                Rotor left_rotor = rotors.at(rotorNames[firstRotor]).Duplicate(0, i);
+                Rotor center_rotor = rotors.at(rotorNames[secondRotor]).Duplicate(0, j);
+                Rotor right_rotor = rotors.at(rotorNames[thirdRotor]).Duplicate(0, k);
 
                 Enigma enigma({left_rotor, center_rotor, right_rotor}, reflector, plugboard);
 
@@ -54,6 +71,8 @@ Setting try_all_keys(const std::string &firstRotor, const std::string &secondRot
         }
     }
 
+    std::cout << best << std::endl;
+
     return best;
 }
 
@@ -62,23 +81,9 @@ bool operator<(const Setting &left, const Setting &right)
     return left.score < right.score;
 }
 
-std::array<std::string, 8> rotorNames = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII"};
-
-char int_to_char(int c)
-{
-    return static_cast<char>(c + 'A');
-}
-
-std::ostream &operator<<(std::ostream &s, const Setting &set)
-{
-    s << rotorNames[set.rotorIndexes[0]] << " " << rotorNames[set.rotorIndexes[1]] << " " << rotorNames[set.rotorIndexes[2]];
-    s << " - " << int_to_char(set.rotorPositions[0]) << " " << int_to_char(set.rotorPositions[1]) << " " << int_to_char(set.rotorPositions[2]);
-    // s << " - " << set.text;
-    return s << " : " << set.score;
-}
-
 void find_rotor_order(const std::string &cipher, int first_disk)
 {
+    std::vector<std::future<Setting>> asyncResults;
     std::vector<Setting> results;
     // for (int i = 4; i < 8; i++)
     // {
@@ -95,14 +100,16 @@ void find_rotor_order(const std::string &cipher, int first_disk)
                 continue;
             std::cout << "Trying " << rotorNames[i] << ", " << rotorNames[j] << ", " << rotorNames[k] << std::endl;
 
-            auto result = try_all_keys(rotorNames[i], rotorNames[j], rotorNames[k], cipher);
-            result.rotorIndexes = {i, j, k};
-            results.push_back(result);
-
-            std::cout << result << std::endl;
+            asyncResults.push_back(std::async(try_all_keys, i, j, k, cipher));
         }
     }
 
+    for (auto&& result: asyncResults)
+    {
+        result.wait();
+        results.push_back(result.get());
+    }
+
     std::sort(results.begin(), results.end());
 
     for (const auto& result: results)