diff --git a/ExampleAIClient.vcxproj b/ExampleAIClient.vcxproj
index d9010e6..164a6a3 100644
--- a/ExampleAIClient.vcxproj
+++ b/ExampleAIClient.vcxproj
@@ -88,19 +88,27 @@
+
+
+
+
+
+
+
+
diff --git a/ExampleAIClient.vcxproj.filters b/ExampleAIClient.vcxproj.filters
index 199b5a2..5f3e183 100644
--- a/ExampleAIClient.vcxproj.filters
+++ b/ExampleAIClient.vcxproj.filters
@@ -33,6 +33,18 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
@@ -50,5 +62,17 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
\ No newline at end of file
diff --git a/Source/CameraControl.cpp b/Source/CameraControl.cpp
new file mode 100644
index 0000000..31f0cb9
--- /dev/null
+++ b/Source/CameraControl.cpp
@@ -0,0 +1,25 @@
+#include "CameraControl.h"
+
+#include
+
+using BWAPI::Broodwar;
+using BWAPI::Position;
+using BWAPI::Unit;
+
+void centerCameraOnPoint(Position p) {
+ if(p == BWAPI::Positions::Unknown) {
+ return;
+ }
+ Broodwar->setScreenPosition(p - Position(300, 200)); //experimental testing
+}
+
+void centerCameraOnUnit(Unit unit) {
+ if(!unit) {
+ return;
+ }
+ Position p = unit->getPosition();
+ if(p == BWAPI::Positions::Unknown) {
+ return;
+ }
+ centerCameraOnPoint(p);
+}
\ No newline at end of file
diff --git a/Source/CameraControl.h b/Source/CameraControl.h
new file mode 100644
index 0000000..ac5367b
--- /dev/null
+++ b/Source/CameraControl.h
@@ -0,0 +1,9 @@
+#ifndef CAMERA_CONTROL_H
+#define CAMERA_CONTROL_H
+
+#include
+
+void centerCameraOnPoint(BWAPI::Position p);
+void centerCameraOnUnit(BWAPI::Unit unit);
+
+#endif
\ No newline at end of file
diff --git a/Source/ChatControl.cpp b/Source/ChatControl.cpp
new file mode 100644
index 0000000..ec54b28
--- /dev/null
+++ b/Source/ChatControl.cpp
@@ -0,0 +1,105 @@
+#define _WINSOCKAPI_ // stops windows.h including winsock.h
+#define NOMINMAX
+
+#include "ChatControl.h"
+
+#include
+
+#include "IRCClient.h"
+#include "CameraControl.h"
+#include "WorkerControl.h"
+#include "Mutex.h"
+
+using namespace BWAPI;
+
+ChatControl::ChatControl(Mutex& gameMutex) : gameMutex(gameMutex) {
+
+}
+
+ChatControl::ChatControl(ChatControl& other) : gameMutex(other.gameMutex) {
+
+}
+
+ChatControl::ChatControl(ChatControl&& control) : gameMutex(control.gameMutex) {
+
+}
+
+ChatControl::~ChatControl() {
+
+}
+
+void ChatControl::operator()(const IRCMessage& message, IRCClient& client) {
+ std::string text = message.parameters.at(message.parameters.size() - 1);
+ LockGuard guard(gameMutex);
+ if(text == "build worker") {
+ Unitset units = Broodwar->self()->getUnits();
+ units.remove_if([](Unit i) { return !i->getType().isResourceDepot(); });
+ if(units.size() > 0) {
+ Unit u = units.rand();
+ u->train(Broodwar->self()->getRace().getWorker());
+ centerCameraOnUnit(u);
+ }
+ } else if(text == "send idle workers to mine") {
+ Unitset units = Broodwar->self()->getUnits();
+ for(auto it = units.begin(); it != units.end(); it++) {
+ if(it->getType().isWorker() && it->isIdle()) {
+ it->gather(it->getClosestUnit(BWAPI::Filter::IsMineralField));
+ centerCameraOnUnit(*it);
+ }
+ }
+ } else if(text == "build supply depot") {
+ Unitset units = Broodwar->self()->getUnits();
+ // Get all our workers
+ units.remove_if([](Unit i) { return !i->getType().isWorker(); });
+ units.remove_if([](Unit i) { return !i->canBuild(); });
+ units.remove_if([](Unit i) { return !i->canBuild(UnitTypes::Terran_Supply_Depot); });
+ if(units.size() > 0) {
+ // Choose a random one
+ Unit worker = units.rand();
+ //Find the closest place to build one
+ buildAtClosestLocation(worker, UnitTypes::Terran_Supply_Depot);
+ centerCameraOnUnit(worker);
+ }
+ } else if(text == "build barracks") {
+ Unitset units = Broodwar->self()->getUnits();
+ // Get all our workers
+ units.remove_if([](Unit i) { return !i->getType().isWorker(); });
+ units.remove_if([](Unit i) { return !i->canBuild(); });
+ units.remove_if([](Unit i) { return !i->canBuild(UnitTypes::Terran_Barracks); });
+ if(units.size() > 0) {
+ // Choose a random one
+ Unit worker = units.rand();
+ //Find the closest place to build one
+ buildAtClosestLocation(worker, UnitTypes::Terran_Barracks);
+ centerCameraOnUnit(worker);
+ }
+ } else if(text == "build marine") {
+ Unitset units = Broodwar->self()->getUnits();
+ units.remove_if([](Unit i) { return i->getType().getID() != UnitTypes::Terran_Barracks; });
+ if(units.size() > 0) {
+ Unit barracks = units.rand();
+ if(barracks->train(UnitTypes::Terran_Marine)) {
+ centerCameraOnUnit(barracks);
+ }
+ }
+ } else if(text == "yolo marines") {
+ Unitset units = Broodwar->self()->getUnits();
+ units.remove_if([](Unit i) { return i->getType().getID() != UnitTypes::Terran_Marine; });
+
+ Unitset enemyUnits = Broodwar->enemies()[0]->getUnits();
+ enemyUnits.remove_if([](Unit i) { return !i->getType().isResourceDepot(); });
+ if(enemyUnits.size() > 0) {
+
+ for(auto it = units.begin(); it != units.end(); it++) {
+ if(!it->attack(PositionOrUnit(enemyUnits.getPosition()))) {
+ std::cout << "unit failed to attack" << std::endl;
+ } else {
+ std::cout << "successful attack!" << std::endl;
+ }
+ centerCameraOnUnit(*it);
+ }
+ } else {
+ std::cout << "nothing to attack" << std::endl;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ChatControl.h b/Source/ChatControl.h
new file mode 100644
index 0000000..a171a22
--- /dev/null
+++ b/Source/ChatControl.h
@@ -0,0 +1,21 @@
+#ifndef CHAT_CONTROL
+#define CHAT_CONTROL
+
+#include "Mutex.h"
+#include "IRCClient.h"
+
+class ChatControl {
+private:
+ Mutex& gameMutex;
+
+ ChatControl& operator=(const ChatControl&) {} //deleted
+public:
+ ChatControl(Mutex& gameMutex);
+ ChatControl(ChatControl& o);
+ ChatControl(ChatControl&&);
+ ~ChatControl();
+
+ void operator()(const IRCMessage& message, IRCClient& client);
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/ExampleAIClient.cpp b/Source/ExampleAIClient.cpp
index 093b3a5..990c856 100644
--- a/Source/ExampleAIClient.cpp
+++ b/Source/ExampleAIClient.cpp
@@ -11,6 +11,8 @@
#include "IRCClient.h"
#include "Thread.h"
#include "Mutex.h"
+#include "ChatControl.h"
+#include "WorkerControl.h"
#include
@@ -18,11 +20,6 @@
using namespace BWAPI;
-void initialMining();
-void handleMessage(const IRCMessage& message, IRCClient& client);
-
-Mutex mutex;
-
void reconnect()
{
while(!BWAPIClient.connect())
@@ -47,8 +44,10 @@ int main(int argc, const char* argv[]) {
std::string nickname = "twitchplaysbw";
std::string username = "twitchplaysbw";
+ Mutex mutex;
+
IRCClient client;
- client.HookIRCCommand("PRIVMSG", handleMessage);
+ client.HookIRCCommand("PRIVMSG", ChatControl(mutex));
if(!client.InitSocket()) {
std::cerr << "Unable to init socket" << std::endl;
@@ -119,198 +118,3 @@ int main(int argc, const char* argv[]) {
return 0;
}
-void centerCameraOnPoint(Position p) {
- if(p == Positions::Unknown) {
- return;
- }
- Broodwar->setScreenPosition(p - Position(300, 200)); //experimental testing
-}
-
-void centerCameraOnUnit(UnitInterface* unit) {
- if(!unit) {
- return;
- }
- Position p = unit->getPosition();
- if(p == Positions::Unknown) {
- return;
- }
- centerCameraOnPoint(p);
-}
-
-void initialMining() {
- //send each worker to the mineral field that is closest to it
- Unitset units = Broodwar->self()->getUnits();
- Unitset minerals = Broodwar->getMinerals();
- for ( Unitset::iterator i = units.begin(); i != units.end(); ++i )
- {
- if ( i->getType().isWorker() )
- {
- Unit closestMineral = NULL;
-
- for( Unitset::iterator m = minerals.begin(); m != minerals.end(); ++m )
- {
- if ( !closestMineral || i->getDistance(*m) < i->getDistance(closestMineral))
- closestMineral = *m;
- }
- if ( closestMineral )
- i->rightClick(closestMineral);
- }
- else if ( i->getType().isResourceDepot() )
- {
- //if this is a center, tell it to build the appropiate type of worker
- i->train(Broodwar->self()->getRace().getWorker());
- }
- }
-}
-
-bool strBeginsWith(const std::string& str, const std::string& begin) {
- return str.substr(0, begin.size()) == begin;
-}
-
-std::vector strSplit(const std::string& str, char splitOn) {
- std::vector ret;
- std::string current;
- for(std::size_t i = 0; i < str.size(); i++) {
- if(str[i] == splitOn) {
- ret.push_back(current);
- current = "";
- } else {
- current.push_back(str[i]);
- }
- }
- ret.push_back(current);
- return std::move(ret);
-}
-
-bool buildAtLocation(Unit worker, UnitType type, TilePosition tile) {
- if(worker->canBuild(type, tile)) {
- Broodwar->drawCircle(CoordinateType::Map, tile.x * 32, tile.y * 32, 1.2 * std::max(type.width(), type.height()), Color(255, 0 , 0));
- Unitset closestOtherUnits = Broodwar->getUnitsInRadius(tile.x * 32, tile.y * 32, 1.2 * std::max(type.width(), type.height()));
- closestOtherUnits.remove_if([worker](Unit u) { return u == worker; });
- if(closestOtherUnits.size() == 0) {
- return worker->build(type, tile);
- }
- }
- return false;
-}
-
-void buildAtClosestLocation(Unit worker, UnitType type) {
- TilePosition tile = worker->getTilePosition();
- if(buildAtLocation(worker, type, tile)) {
- std::cout << "built successfully!" << std::endl;
- return;
- }
- for(int radius = 1; radius < 200; radius++) {
- //Spiral out
- tile.x++;
- for(int j = 0; j < radius; j++) {
- tile.x--;
- tile.y--;
- if(buildAtLocation(worker, type, tile)) {
- std::cout << "built successfully!" << std::endl;
- return;
- }
- }
- for(int j = 0; j < radius; j++) {
- tile.x--;
- tile.y++;
- if(buildAtLocation(worker, type, tile)) {
- std::cout << "built successfully!" << std::endl;
- return;
- }
- }
- for(int j = 0; j < radius; j++) {
- tile.x++;
- tile.y++;
- if(buildAtLocation(worker, type, tile)) {
- std::cout << "built successfully!" << std::endl;
- return;
- }
- }
- for(int j = 0; j < radius; j++) {
- tile.x++;
- tile.y--;
- if(buildAtLocation(worker, type, tile)) {
- std::cout << "built successfully!" << std::endl;
- return;
- }
- }
- }
-}
-
-void handleMessage(const IRCMessage& message, IRCClient& client) {
- std::string text = message.parameters.at(message.parameters.size() - 1);
- LockGuard guard(mutex);
- if(text == "build worker") {
- Unitset units = Broodwar->self()->getUnits();
- units.remove_if([](Unit i) { return !i->getType().isResourceDepot(); });
- if(units.size() > 0) {
- Unit u = units.rand();
- u->train(Broodwar->self()->getRace().getWorker());
- centerCameraOnUnit(u);
- }
- } else if(text == "send idle workers to mine") {
- Unitset units = Broodwar->self()->getUnits();
- for(auto it = units.begin(); it != units.end(); it++) {
- if(it->getType().isWorker() && it->isIdle()) {
- it->gather(it->getClosestUnit(Filter::IsMineralField));
- centerCameraOnUnit(*it);
- }
- }
- } else if(text == "build supply depot") {
- Unitset units = Broodwar->self()->getUnits();
- // Get all our workers
- units.remove_if([](Unit i) { return !i->getType().isWorker(); });
- units.remove_if([](Unit i) { return !i->canBuild(); });
- units.remove_if([](Unit i) { return !i->canBuild(UnitTypes::Terran_Supply_Depot); });
- if(units.size() > 0) {
- // Choose a random one
- Unit worker = units.rand();
- //Find the closest place to build one
- buildAtClosestLocation(worker, UnitTypes::Terran_Supply_Depot);
- centerCameraOnUnit(worker);
- }
- } else if(text == "build barracks") {
- Unitset units = Broodwar->self()->getUnits();
- // Get all our workers
- units.remove_if([](Unit i) { return !i->getType().isWorker(); });
- units.remove_if([](Unit i) { return !i->canBuild(); });
- units.remove_if([](Unit i) { return !i->canBuild(UnitTypes::Terran_Barracks); });
- if(units.size() > 0) {
- // Choose a random one
- Unit worker = units.rand();
- //Find the closest place to build one
- buildAtClosestLocation(worker, UnitTypes::Terran_Barracks);
- centerCameraOnUnit(worker);
- }
- } else if(text == "build marine") {
- Unitset units = Broodwar->self()->getUnits();
- units.remove_if([](Unit i) { return i->getType().getID() != UnitTypes::Terran_Barracks; });
- if(units.size() > 0) {
- Unit barracks = units.rand();
- if(barracks->train(UnitTypes::Terran_Marine)) {
- centerCameraOnUnit(barracks);
- }
- }
- } else if(text == "yolo marines") {
- Unitset units = Broodwar->self()->getUnits();
- units.remove_if([](Unit i) { return i->getType().getID() != UnitTypes::Terran_Marine; });
-
- Unitset enemyUnits = Broodwar->enemies()[0]->getUnits();
- enemyUnits.remove_if([](Unit i) { return !i->getType().isResourceDepot(); });
- if(enemyUnits.size() > 0) {
-
- for(auto it = units.begin(); it != units.end(); it++) {
- if(!it->attack(PositionOrUnit(enemyUnits.getPosition()))) {
- std::cout << "unit failed to attack" << std::endl;
- } else {
- std::cout << "successful attack!" << std::endl;
- }
- centerCameraOnUnit(*it);
- }
- } else {
- std::cout << "nothing to attack" << std::endl;
- }
- }
-}
-
diff --git a/Source/IRCClient.cpp b/Source/IRCClient.cpp
index 5f4aa2b..7654325 100644
--- a/Source/IRCClient.cpp
+++ b/Source/IRCClient.cpp
@@ -20,23 +20,11 @@
#include "IRCSocket.h"
#include "IRCClient.h"
#include "IRCHandler.h"
+#include "StringOperations.h"
using std::string;
using std::vector;
-vector split(const string& text, char sep)
-{
- vector tokens;
- size_t start = 0, end = 0;
- while ((end = text.find(sep, start)) != string::npos)
- {
- tokens.push_back(text.substr(start, end - start));
- start = end + 1;
- }
- tokens.push_back(text.substr(start));
- return tokens;
-}
-
bool IRCClient::InitSocket()
{
return _socket.Init();
@@ -157,12 +145,12 @@ void IRCClient::Parse(const string& _data)
CallHook(command, ircMessage);
}
-void IRCClient::HookIRCCommand(const string& command, void (*function)(const IRCMessage& /*message*/, IRCClient& /*client*/))
+void IRCClient::HookIRCCommand(const string& command, std::function&& function)
{
IRCCommandHook hook;
hook.command = command;
- hook.function = function;
+ hook.function = std::move(function);
_hooks.push_back(hook);
}
@@ -176,7 +164,7 @@ void IRCClient::CallHook(const string& command, const IRCMessage& message)
{
if (itr->command == command)
{
- (*(itr->function))(message, *this);
+ itr->function(message, *this);
break;
}
}
diff --git a/Source/IRCClient.h b/Source/IRCClient.h
index a90910a..f236d37 100644
--- a/Source/IRCClient.h
+++ b/Source/IRCClient.h
@@ -21,12 +21,12 @@
#include
#include
#include
+#include
#include "IRCSocket.h"
+#include "StringOperations.h"
class IRCClient;
-extern std::vector split(const std::string&, char);
-
struct IRCCommandPrefix
{
void Parse(const std::string& data)
@@ -73,7 +73,7 @@ struct IRCCommandHook
IRCCommandHook() : function(NULL) {};
std::string command;
- void (*function)(const IRCMessage& /*message*/, IRCClient& /*client*/);
+ std::function function;
};
class IRCClient
@@ -92,7 +92,7 @@ class IRCClient
void ReceiveData();
- void HookIRCCommand(const std::string& /*command*/, void (*function)(const IRCMessage& /*message*/, IRCClient& /*client*/));
+ void HookIRCCommand(const std::string& /*command*/, std::function&& function);
void Parse(const std::string& /*data*/);
diff --git a/Source/StringOperations.cpp b/Source/StringOperations.cpp
new file mode 100644
index 0000000..6cdc545
--- /dev/null
+++ b/Source/StringOperations.cpp
@@ -0,0 +1,19 @@
+#include "StringOperations.h"
+
+#include
+#include
+
+using std::string;
+using std::vector;
+
+vector split(const string& text, char sep) {
+ vector tokens;
+ size_t start = 0, end = 0;
+ while ((end = text.find(sep, start)) != string::npos)
+ {
+ tokens.push_back(text.substr(start, end - start));
+ start = end + 1;
+ }
+ tokens.push_back(text.substr(start));
+ return tokens;
+}
\ No newline at end of file
diff --git a/Source/StringOperations.h b/Source/StringOperations.h
new file mode 100644
index 0000000..c33dcc9
--- /dev/null
+++ b/Source/StringOperations.h
@@ -0,0 +1,9 @@
+#ifndef STRING_OPERATIONS_H
+#define STRING_OPERATIONS_H
+
+#include
+#include
+
+std::vector split(const std::string&, char);
+
+#endif
\ No newline at end of file
diff --git a/Source/WorkerControl.cpp b/Source/WorkerControl.cpp
new file mode 100644
index 0000000..557eef9
--- /dev/null
+++ b/Source/WorkerControl.cpp
@@ -0,0 +1,94 @@
+#include "WorkerControl.h"
+
+#include
+
+#include
+
+using BWAPI::Unitset;
+using BWAPI::Unit;
+using BWAPI::Broodwar;
+using BWAPI::UnitType;
+using BWAPI::TilePosition;
+using BWAPI::Color;
+
+void initialMining() {
+ //send each worker to the mineral field that is closest to it
+ Unitset units = Broodwar->self()->getUnits();
+ Unitset minerals = Broodwar->getMinerals();
+ for ( Unitset::iterator i = units.begin(); i != units.end(); ++i )
+ {
+ if ( i->getType().isWorker() )
+ {
+ Unit closestMineral = NULL;
+
+ for( Unitset::iterator m = minerals.begin(); m != minerals.end(); ++m )
+ {
+ if ( !closestMineral || i->getDistance(*m) < i->getDistance(closestMineral))
+ closestMineral = *m;
+ }
+ if ( closestMineral )
+ i->rightClick(closestMineral);
+ }
+ else if ( i->getType().isResourceDepot() )
+ {
+ //if this is a center, tell it to build the appropiate type of worker
+ i->train(Broodwar->self()->getRace().getWorker());
+ }
+ }
+}
+
+bool buildAtLocation(Unit worker, UnitType type, TilePosition tile) {
+ if(worker->canBuild(type, tile)) {
+ Broodwar->drawCircle(BWAPI::CoordinateType::Map, tile.x * 32, tile.y * 32, 1.2 * std::max(type.width(), type.height()), Color(255, 0 , 0));
+ Unitset closestOtherUnits = Broodwar->getUnitsInRadius(tile.x * 32, tile.y * 32, 1.2 * std::max(type.width(), type.height()));
+ closestOtherUnits.remove_if([worker](Unit u) { return u == worker; });
+ if(closestOtherUnits.size() == 0) {
+ return worker->build(type, tile);
+ }
+ }
+ return false;
+}
+
+void buildAtClosestLocation(Unit worker, UnitType type) {
+ TilePosition tile = worker->getTilePosition();
+ if(buildAtLocation(worker, type, tile)) {
+ std::cout << "built successfully!" << std::endl;
+ return;
+ }
+ for(int radius = 1; radius < 200; radius++) {
+ //Spiral out
+ tile.x++;
+ for(int j = 0; j < radius; j++) {
+ tile.x--;
+ tile.y--;
+ if(buildAtLocation(worker, type, tile)) {
+ std::cout << "built successfully!" << std::endl;
+ return;
+ }
+ }
+ for(int j = 0; j < radius; j++) {
+ tile.x--;
+ tile.y++;
+ if(buildAtLocation(worker, type, tile)) {
+ std::cout << "built successfully!" << std::endl;
+ return;
+ }
+ }
+ for(int j = 0; j < radius; j++) {
+ tile.x++;
+ tile.y++;
+ if(buildAtLocation(worker, type, tile)) {
+ std::cout << "built successfully!" << std::endl;
+ return;
+ }
+ }
+ for(int j = 0; j < radius; j++) {
+ tile.x++;
+ tile.y--;
+ if(buildAtLocation(worker, type, tile)) {
+ std::cout << "built successfully!" << std::endl;
+ return;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/WorkerControl.h b/Source/WorkerControl.h
new file mode 100644
index 0000000..30f8a69
--- /dev/null
+++ b/Source/WorkerControl.h
@@ -0,0 +1,10 @@
+#ifndef WORKER_CONTROL_H
+#define WORKER_CONTROL_H
+
+#include
+
+void initialMining();
+bool buildAtLocation(BWAPI::Unit worker, BWAPI::UnitType type, BWAPI::TilePosition tile);
+void buildAtClosestLocation(BWAPI::Unit worker, BWAPI::UnitType type);
+
+#endif
\ No newline at end of file