Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "VP.h"
- #include <iostream>
- #include <list>
- #include <map>
- #include <string>
- using namespace std;
- const char* UNIVERSE_HOST = "universe.virtualparadise.org";
- int UNIVERSE_PORT = 57000;
- struct Object {
- Object() {}
- Object(int objectId, int userId,
- float objectX, float objectY, float objectZ,
- float objectRotationX, float objectRotationY, float objectRotationZ,
- float objectRotationAngle,
- int objectType,
- string objectModel, string objectDescription, string objectAction) :
- mObjectId(objectId), mUserId(userId),
- mX(objectX), mY(objectY), mZ(objectZ),
- mRotationX(objectRotationX),
- mRotationY(objectRotationY),
- mRotationZ(objectRotationZ),
- mRotationAngle(objectRotationAngle),
- mType(objectType),
- mModel(objectModel),
- mDescription(objectDescription),
- mAction(objectAction) {
- }
- int mObjectId;
- int mUserId;
- float mX, mY, mZ;
- float mRotationX, mRotationY, mRotationZ, mRotationAngle;
- int mType;
- string mModel, mDescription, mAction;
- };
- void buildObject(VPInstance instance, const Object& o) {
- vp_int_set(instance, VP_OBJECT_TYPE, o.mType);
- vp_float_set(instance, VP_OBJECT_X, o.mX);
- vp_float_set(instance, VP_OBJECT_Y, o.mY);
- vp_float_set(instance, VP_OBJECT_Z, o.mZ);
- vp_float_set(instance, VP_OBJECT_ROTATION_X, o.mRotationX);
- vp_float_set(instance, VP_OBJECT_ROTATION_Y, o.mRotationY);
- vp_float_set(instance, VP_OBJECT_ROTATION_Z, o.mRotationZ);
- vp_float_set(instance, VP_OBJECT_ROTATION_ANGLE, o.mRotationAngle);
- vp_string_set(instance, VP_OBJECT_MODEL, o.mModel.c_str());
- vp_string_set(instance, VP_OBJECT_DESCRIPTION, o.mDescription.c_str());
- vp_string_set(instance, VP_OBJECT_ACTION, o.mAction.c_str());
- vp_object_add(instance);
- }
- class TicTacToeBot {
- public:
- TicTacToeBot(VPInstance instance, const string& ownerName) :
- mInstance(instance), mOwnerName(ownerName), mPhase(WAITING_FOR_OWNER) {
- }
- void onAvatarAdd(const string& name, int session, int userId,
- float x, float y, float z) {
- mUserNamesBySession[session] = name;
- if (mPhase == WAITING_FOR_OWNER && name == mOwnerName) {
- mOwnerSession = session;
- mOwnerId = userId;
- joinOwner(x, y, z);
- }
- }
- void onObjectClick(int avatarSession, int objectId, float hitX, float hitY,
- float hitZ) {
- if (avatarSession == mOwnerSession && mPhase == PROMPTING_FOR_GRID) {
- mCellObjects[mWaitingForCell] = mObjectsById[objectId];
- if (mWaitingForCell < 8) {
- promptForGrid(mWaitingForCell + 1);
- } else {
- promptBuildXs();
- }
- }
- if (avatarSession == mOwnerSession && mPhase == MATCHING_XS) {
- mXPieces[mWaitingForCell] = mObjectsById[objectId];
- mPieceObjectIds.push_back(objectId);
- if (mWaitingForCell < 8) {
- promptMatchX(mWaitingForCell + 1);
- } else {
- deletePieces();
- promptBuildOs();
- }
- }
- if (avatarSession == mOwnerSession && mPhase == MATCHING_OS) {
- mOPieces[mWaitingForCell] = mObjectsById[objectId];
- mPieceObjectIds.push_back(objectId);
- if (mWaitingForCell < 8) {
- promptMatchO(mWaitingForCell + 1);
- }
- else {
- deletePieces();
- resetGame();
- announceReady();
- }
- }
- int cell = cellForObject(objectId);
- if (cell != -1) {
- if (mPhase == READY_PLAYER_ONE) {
- mPlayer1Session = avatarSession;
- buildGamePiece(cell, true);
- mGameBoard[cell] = 1;
- mPhase = READY_PLAYER_TWO;
- } else if (mPhase == READY_PLAYER_TWO &&
- avatarSession != mPlayer1Session &&
- mGameBoard[cell] == 0) {
- mPlayer2Session = avatarSession;
- buildGamePiece(cell, false);
- mGameBoard[cell] = -1;
- mPhase = ONGOING_GAME;
- } else if (mPhase == ONGOING_GAME &&
- avatarSession == mPlayer1Session &&
- mPlayer1sTurn &&
- mGameBoard[cell] == 0) {
- mPlayer1sTurn = false;
- buildGamePieceAndBlock(cell, true);
- mGameBoard[cell] = 1;
- } else if (mPhase == ONGOING_GAME &&
- avatarSession == mPlayer2Session &&
- !mPlayer1sTurn &&
- mGameBoard[cell] == 0) {
- mPlayer1sTurn = true;
- buildGamePieceAndBlock(cell, false);
- mGameBoard[cell] = -1;
- }
- }
- }
- void onObject(const Object& object) {
- if (isSetupBuildingPhase(mPhase) && object.mUserId == mOwnerId) {
- mObjectsById[object.mObjectId] = object;
- }
- }
- void onObjectChange(const Object& object) {
- // No need to treat scanning differently from subscribing.
- onObject(object);
- }
- void onCellEnd() {
- if (++mScanCell < 100) {
- int nextX = mScanStartX + (mScanCell / 10);
- int nextZ = mScanStartZ + (mScanCell % 10);
- vp_query_cell(mInstance, nextX, nextZ);
- } else {
- mPhase = WATCHING_DELETES;
- cout << "Found " << mObjectsById.size() << " of your objects." << endl;
- whisperOwner("Now I'm going to scan how to rebuild your board design.");
- whisperOwner("I need you to delete each object one at a time --");
- whisperOwner("but don't worry, they'll come right back when you");
- whisperOwner("say 'done'");
- }
- }
- void onObjectDelete(int avatarSession, int objectId) {
- if (mPhase != WATCHING_DELETES) {
- return;
- }
- if (mObjectsById.find(objectId) != mObjectsById.end()) {
- Object object = mObjectsById[objectId];
- mBoardObjects.push_back(object);
- whisperOwner(string("Got it: you deleted a ") + object.mModel);
- }
- }
- void onAvatarDelete(int session) {
- if (session == mPlayer1Session || session == mPlayer2Session) {
- resetGame();
- }
- }
- void onChat(int session, string name, string message) {
- if (session == mOwnerSession) {
- if (mPhase == WATCHING_DELETES && message == "done") {
- cout << "Got " << mBoardObjects.size() << " board objects" << endl;
- rebuildBoard();
- }
- if (mPhase == WAITING_FOR_XS && message == "ready") {
- promptMatchX(0);
- }
- if (mPhase == WAITING_FOR_OS && message == "ready") {
- promptMatchO(0);
- }
- }
- }
- void postObjectAdded(int objectId) {
- if (objectsBuiltInPhaseAreGamePieces(mPhase)) {
- mPieceObjectIds.push_back(objectId);
- }
- }
- const list<Object> getBlockingBuildQueue() {
- return mBlockingBuildQueue;
- }
- void postBuiltQueue(list<Object> builtObjects) {
- mBlockingBuildQueue.clear();
- if (objectsBuiltInPhaseAreGamePieces(mPhase)) {
- for (list<Object>::iterator i = builtObjects.begin();
- i != builtObjects.end(); ++i) {
- mPieceObjectIds.push_back(i->mObjectId);
- }
- }
- if (mPhase == BLOCKED_FOR_REBUILD) {
- for (list<Object>::iterator i = builtObjects.begin();
- i != builtObjects.end(); ++i) {
- mObjectsById[i->mObjectId] = *i;
- }
- mPhase = PROMPTING_FOR_GRID;
- promptForGrid(0);
- }
- if (mPhase == ONGOING_GAME) {
- int winner = evaluateBoard();
- if (winner != 0) {
- gameOver(winner, false);
- }
- if (mPieceObjectIds.size() == 9) {
- gameOver(0, true);
- }
- }
- }
- private:
- VPInstance mInstance;
- string mOwnerName;
- int mOwnerSession;
- int mOwnerId;
- enum Phase {
- WAITING_FOR_OWNER,
- SCANNING_OBJECTS,
- WATCHING_DELETES,
- BLOCKED_FOR_REBUILD,
- PROMPTING_FOR_GRID,
- WAITING_FOR_XS,
- MATCHING_XS,
- WAITING_FOR_OS,
- MATCHING_OS,
- READY_PLAYER_ONE,
- READY_PLAYER_TWO,
- ONGOING_GAME
- };
- Phase mPhase;
- int mScanStartX, mScanStartZ;
- int mScanCell;
- map<int, Object> mObjectsById;
- map<int, string> mUserNamesBySession;
- list<Object> mBoardObjects;
- int mWaitingForCell;
- Object mCellObjects[9];
- Object mXPieces[9];
- Object mOPieces[9];
- list<int> mPieceObjectIds;
- list<Object> mBlockingBuildQueue;
- int mPlayer1Session;
- int mPlayer2Session;
- bool mPlayer1sTurn;
- int mGameBoard[9];
- void whisperOwner(string msg) {
- vp_console_message(mInstance, mOwnerSession, "", msg.c_str(), 0, 0, 0, 0);
- }
- void joinOwner(float x, float y, float z) {
- vp_float_set(mInstance, VP_MY_X, x);
- vp_float_set(mInstance, VP_MY_Y, y);
- vp_float_set(mInstance, VP_MY_Z, z);
- vp_state_change(mInstance);
- mPhase = SCANNING_OBJECTS;
- whisperOwner("Hi! One sec, scanning.");
- startScan(x, y, z);
- }
- void startScan(float x, float y, float z) {
- mPhase = SCANNING_OBJECTS;
- mScanCell = 0;
- mScanStartX = x - 5;
- mScanStartZ = z - 5;
- vp_query_cell(mInstance, mScanStartX, mScanStartZ);
- }
- void rebuildBoard() {
- whisperOwner("Rebuilding...");
- for (list<Object>::iterator i = mBoardObjects.begin();
- i != mBoardObjects.end(); ++i) {
- mBlockingBuildQueue.push_back(*i);
- }
- mPhase = BLOCKED_FOR_REBUILD;
- }
- void promptForGrid(int cell) {
- whisperOwner("Please click on the " + nameCell(cell) + " grid cell");
- mWaitingForCell = cell;
- }
- string nameCell(int cell) {
- if (cell == 4) {
- return "center";
- }
- string row;
- if (cell < 3) {
- row = "top";
- } else if (cell > 5) {
- row = "bottom";
- } else {
- row = "middle";
- }
- string column;
- if (cell % 3 == 0) {
- column = "left";
- } else if (cell % 3 == 1) {
- column = "middle";
- } else {
- column = "right";
- }
- return row + " " + column;
- }
- void promptBuildXs() {
- whisperOwner("Now build X's in each grid cell, then say 'ready'");
- mPhase = WAITING_FOR_XS;
- }
- void promptMatchX(int cell) {
- mPhase = MATCHING_XS;
- whisperOwner("Please click on the " + nameCell(cell) + " 'X' piece");
- mWaitingForCell = cell;
- }
- bool isSetupBuildingPhase(Phase phase) {
- // We need to watch builds in these phases in case they're part of the
- // initial construction.
- return mPhase == SCANNING_OBJECTS || mPhase == WAITING_FOR_XS ||
- mPhase == WAITING_FOR_OS;
- }
- bool objectsBuiltInPhaseAreGamePieces(Phase phase) {
- return phase != WATCHING_DELETES &&
- phase != BLOCKED_FOR_REBUILD; // Don't count rebuilding the board.
- }
- void deletePieces() {
- for (list<int>::iterator i = mPieceObjectIds.begin();
- i != mPieceObjectIds.end(); ++i) {
- vp_object_delete(mInstance, *i);
- }
- mPieceObjectIds.clear();
- }
- void promptBuildOs() {
- whisperOwner("Now build O's in each grid cell, then say 'ready'");
- mPhase = WAITING_FOR_OS;
- }
- void promptMatchO(int cell) {
- mPhase = MATCHING_OS;
- whisperOwner("Please click on the " + nameCell(cell) + " 'O' piece");
- mWaitingForCell = cell;
- }
- void resetGame() {
- mPhase = READY_PLAYER_ONE;
- mPlayer1Session = -1;
- mPlayer2Session = -1;
- mPlayer1sTurn = true;
- for (int i = 0; i < 9; ++i) {
- mGameBoard[i] = 0;
- }
- deletePieces();
- }
- void announceReady() {
- whisperOwner("Ready"); // a little premature to realllly announce
- }
- void buildGamePiece(int cell, bool asX) {
- Object& originalObject = asX ? mXPieces[cell] : mOPieces[cell];
- buildObject(mInstance, originalObject);
- }
- void buildGamePieceAndBlock(int cell, bool asX) {
- Object& originalObject = asX ? mXPieces[cell] : mOPieces[cell];
- mBlockingBuildQueue.push_back(originalObject);
- }
- int cellForObject(int objectId) {
- for (int i = 0; i < 9; ++i) {
- if (mCellObjects[i].mObjectId == objectId) {
- return i;
- }
- }
- return -1;
- }
- void gameOver(int winner, bool tie) {
- if (tie) {
- resetGame();
- return;
- }
- vp_say(mInstance, "Winner:");
- string winnerName = (winner > 0) ? mUserNamesBySession[mPlayer1Session] :
- mUserNamesBySession[mPlayer2Session];
- vp_say(mInstance, winnerName.c_str());
- resetGame();
- }
- int evaluateBoard() {
- if (playerWins(1)) {
- return 1;
- }
- if (playerWins(-1)) {
- return -1;
- }
- return 0;
- }
- bool playerWins(int player) {
- for (int row = 0; row < 3; ++row) {
- bool winsOnRow = true;
- for (int col = 0; col < 3; ++col) {
- if (mGameBoard[row * 3 + col] != player) {
- winsOnRow = false;
- break;
- }
- }
- if (winsOnRow) {
- return true;
- }
- }
- for (int col = 0; col < 3; ++col) {
- bool winsOnCol = true;
- for (int row = 0; row < 3; ++row) {
- if (mGameBoard[row * 3 + col] != player) {
- winsOnCol = false;
- break;
- }
- }
- if (winsOnCol) {
- return true;
- }
- }
- return (mGameBoard[0] == player && mGameBoard[4] == player && mGameBoard[8] == player) ||
- (mGameBoard[2] == player && mGameBoard[4] == player && mGameBoard[6] == player);
- }
- };
- TicTacToeBot *BOT;
- void event_avatar_add(VPInstance instance) {
- string avatarName(vp_string(instance, VP_AVATAR_NAME));
- int avatarSession = vp_int(instance, VP_AVATAR_SESSION);
- int userId = vp_int(instance, VP_USER_ID);
- float avatarX = vp_float(instance, VP_AVATAR_X);
- float avatarY = vp_float(instance, VP_AVATAR_Y);
- float avatarZ = vp_float(instance, VP_AVATAR_Z);
- BOT->onAvatarAdd(avatarName, avatarSession, userId,
- avatarX, avatarY, avatarZ);
- }
- void event_object_click(VPInstance instance) {
- int avatarSession = vp_int(instance, VP_AVATAR_SESSION);
- int objectId = vp_int(instance, VP_OBJECT_ID);
- float clickHitX = vp_float(instance, VP_CLICK_HIT_X);
- float clickHitY = vp_float(instance, VP_CLICK_HIT_Y);
- float clickHitZ = vp_float(instance, VP_CLICK_HIT_Z);
- BOT->onObjectClick(avatarSession, objectId, clickHitX, clickHitY, clickHitZ);
- }
- void event_object(VPInstance instance) {
- int objectId = vp_int(instance, VP_OBJECT_ID);
- int userId = vp_int(instance, VP_OBJECT_USER_ID);
- float objectX = vp_float(instance, VP_OBJECT_X);
- float objectY = vp_float(instance, VP_OBJECT_Y);
- float objectZ = vp_float(instance, VP_OBJECT_Z);
- float objectRotationX = vp_float(instance, VP_OBJECT_ROTATION_X);
- float objectRotationY = vp_float(instance, VP_OBJECT_ROTATION_Y);
- float objectRotationZ = vp_float(instance, VP_OBJECT_ROTATION_Z);
- float objectRotationAngle = vp_float(instance, VP_OBJECT_ROTATION_ANGLE);
- int objectType = vp_int(instance, VP_OBJECT_TYPE);
- string objectModel =
- string(vp_string(instance, VP_OBJECT_MODEL));
- string objectDescription =
- string(vp_string(instance, VP_OBJECT_DESCRIPTION));
- string objectAction =
- string(vp_string(instance, VP_OBJECT_ACTION));
- Object object(objectId, userId, objectX, objectY, objectZ, objectRotationX,
- objectRotationY, objectRotationZ, objectRotationAngle, objectType,
- objectModel, objectDescription, objectAction);
- BOT->onObject(object);
- }
- void event_cell_end(VPInstance instance) {
- BOT->onCellEnd();
- }
- void event_object_delete(VPInstance instance) {
- int session = vp_int(instance, VP_AVATAR_SESSION);
- int objectId = vp_int(instance, VP_OBJECT_ID);
- BOT->onObjectDelete(session, objectId);
- }
- void event_chat(VPInstance instance) {
- int session = vp_int(instance, VP_AVATAR_SESSION);
- string name = vp_string(instance, VP_AVATAR_NAME);
- string message = vp_string(instance, VP_CHAT_MESSAGE);
- BOT->onChat(session, name, message);
- }
- void event_object_change(VPInstance instance) {
- int objectId = vp_int(instance, VP_OBJECT_ID);
- int userId = vp_int(instance, VP_OBJECT_USER_ID);
- int time = vp_int(instance, VP_OBJECT_TIME);
- float objectX = vp_float(instance, VP_OBJECT_X);
- float objectY = vp_float(instance, VP_OBJECT_Y);
- float objectZ = vp_float(instance, VP_OBJECT_Z);
- float objectRotationX = vp_float(instance, VP_OBJECT_ROTATION_X);
- float objectRotationY = vp_float(instance, VP_OBJECT_ROTATION_Y);
- float objectRotationZ = vp_float(instance, VP_OBJECT_ROTATION_Z);
- float objectRotationAngle = vp_float(instance, VP_OBJECT_ROTATION_ANGLE);
- int objectType = vp_int(instance, VP_OBJECT_TYPE);
- string objectModel =
- string(vp_string(instance, VP_OBJECT_MODEL));
- string objectDescription =
- string(vp_string(instance, VP_OBJECT_DESCRIPTION));
- string objectAction =
- string(vp_string(instance, VP_OBJECT_ACTION));
- Object object(objectId, userId, objectX, objectY, objectZ, objectRotationX,
- objectRotationY, objectRotationZ, objectRotationAngle, objectType,
- objectModel, objectDescription, objectAction);
- BOT->onObjectChange(object);
- }
- void event_avatar_delete(VPInstance instance) {
- int session = vp_int(instance, VP_AVATAR_SESSION);
- BOT->onAvatarDelete(session);
- }
- bool blockedAtTopLevel;
- int lastBlockResult;
- void callback_object_add(VPInstance instance, int cbType, int data) {
- int objectId = vp_int(instance, VP_OBJECT_ID);
- if (blockedAtTopLevel) {
- blockedAtTopLevel = false;
- lastBlockResult = objectId;
- } else {
- BOT->postObjectAdded(objectId);
- }
- }
- int main(int argc, const char* argv[]) {
- int rc;
- if (rc = vp_init()) {
- cout << "Unable to initialize API: " << rc << endl;
- return -1;
- }
- VPInstance instance = vp_create();
- if (rc = vp_connect_universe(instance, UNIVERSE_HOST, UNIVERSE_PORT)) {
- cout << "Couldn't connect to universe: " << rc << endl;
- return -1;
- }
- cout << "Before you begin, you'll need to build an empty board." << endl;
- cout << "Any design will do as long as there's a 3x3 grid." << endl;
- cout << "When you're ready, stand next to it -- the bot will join when it gets"
- << " started up, and it'll need to find your build." << endl << endl;
- // Sorry guys, old-school.
- string username, password, world;
- cout << "Username: ";
- cin >> username;
- cout << "Password: ";
- cin >> password;
- cout << "World: ";
- cin >> world;
- if (rc = vp_login(instance, username.c_str(), password.c_str(), "Crowbot")) {
- cout << "Couldn't login: " << rc << endl;
- return -1;
- }
- if (rc = vp_enter(instance, world.c_str())) {
- cout << "Couldn't enter world: " << rc << endl;
- return -1;
- }
- vp_event_set(instance, VP_EVENT_AVATAR_ADD, event_avatar_add);
- vp_event_set(instance, VP_EVENT_OBJECT_CLICK, event_object_click);
- vp_event_set(instance, VP_EVENT_OBJECT, event_object);
- vp_event_set(instance, VP_EVENT_CELL_END, event_cell_end);
- vp_event_set(instance, VP_EVENT_OBJECT_DELETE, event_object_delete);
- vp_event_set(instance, VP_EVENT_CHAT, event_chat);
- vp_event_set(instance, VP_EVENT_OBJECT_CHANGE, event_object_change);
- vp_event_set(instance, VP_EVENT_AVATAR_DELETE, event_avatar_delete);
- vp_callback_set(instance, VP_CALLBACK_OBJECT_ADD, callback_object_add);
- vp_state_change(instance);
- BOT = new TicTacToeBot(instance, username);
- list<Object> blockingBuildResults;
- while (!vp_wait(instance, 0)) {
- list<Object> blockingBuildQueue = BOT->getBlockingBuildQueue();
- if (!blockingBuildQueue.empty()) {
- while (!blockingBuildQueue.empty()) {
- Object o = blockingBuildQueue.front();
- blockingBuildQueue.pop_front();
- blockedAtTopLevel = true;
- buildObject(instance, o);
- while (blockedAtTopLevel) {
- vp_wait(instance, 0);
- }
- o.mObjectId = lastBlockResult;
- blockingBuildResults.push_back(o);
- }
- BOT->postBuiltQueue(blockingBuildResults);
- blockingBuildResults.clear();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement