Loading ttt_interface/HttpConnect.cpp 0 → 100644 +70 −0 Original line number Diff line number Diff line // // Created by Ari on 10/1/24. // #include "HttpConnect.h" #include <iostream> #include <string> #include <cstring> #include <unistd.h> #include <netdb.h> #include <sys/socket.h> #include <arpa/inet.h> using namespace std; string HttpConnect::makeRequest(string host, string path, string port) { // Step 1: Create a socket int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { throw new HttpConnect::ConnectionError("Failed to create socket"); } // Step 2: Resolve hostname to an IP address struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; // IPv4 hints.ai_socktype = SOCK_STREAM; // TCP if (getaddrinfo(host.c_str(), port.c_str(), &hints, &res) != 0) { close(sock); throw new HttpConnect::ConnectionError("Failed to resolve hostname"); } // Step 3: Connect to the server if (connect(sock, res->ai_addr, res->ai_addrlen) != 0) { close(sock); throw new HttpConnect::ConnectionError("Failed to connect to server"); } freeaddrinfo(res); // Free memory that is no longer needed after connecting // Step 4: Send HTTP GET request std::string request = "GET " + path + " HTTP/1.1\r\n" "Host: " + host + "\r\n" "Connection: close\r\n\r\n"; if (send(sock, request.c_str(), request.size(), 0) == -1) { close(sock); throw new HttpConnect::ConnectionError("Failed to send request"); } // Step 5: Receive and print the response const int buffer_size = 4096; char buffer[buffer_size]; std::string response; ssize_t bytesReceived; while ((bytesReceived = recv(sock, buffer, buffer_size - 1, 0)) > 0) { buffer[bytesReceived] = '\0'; // Null-terminate the buffer response.append(buffer); } if (bytesReceived < 0) { close(sock); throw new HttpConnect::ConnectionError("Error receiving response"); } else { close(sock); return response; } } No newline at end of file ttt_interface/HttpConnect.h 0 → 100644 +30 −0 Original line number Diff line number Diff line // // Created by Ari Trachtenberg on 10/1/24, based on ChatGPT. // #include <iostream> using namespace std; #ifndef HW3_STAFF_HTTPCONNECT_H #define HW3_STAFF_HTTPCONNECT_H class HttpConnect { public: // METHODS /** * Makes a request from https://[host]:[port]/[path] and returns the response. * @param host The host to which to connect. * @param port The port on that host to which to connect. * @param path The path to request on that host. * @return The response to the query. * @throws ConnectionError upon an error. */ static string makeRequest(string host, string path, string port = "80"); // SUBCLASSES class ConnectionError:public runtime_error { public: ConnectionError(string err): runtime_error(err) {} }; }; #endif //HW3_STAFF_HTTPCONNECT_H ttt_interface/ttt.cpp 0 → 100644 +216 −0 Original line number Diff line number Diff line // // Created by Ari on 10/1/24. // #include <iostream> #include <iomanip> #include <sstream> #include <string> #include <map> #include "HttpConnect.h" #include "ttt.h" // HELPERS - mostly by ChatGPT // trim whitespace std::string trim(const std::string& str) { size_t start = str.find_first_not_of(" \t\n\r\f\v"); size_t end = str.find_last_not_of(" \t\n\r\f\v"); return (start == std::string::npos || end == std::string::npos) ? "" : str.substr(start, end - start + 1); } // Function to remove surrounding quotes from a string std::string removeQuotes(const std::string& str) { if (str.front() == '"' && str.back() == '"') { return str.substr(1, str.size() - 2); } return str; } // Basic JSON parser for flat key-value pairs map<string, string> parseJson(const std::string& jsonString) { map<string, string> result; string trimmedJson = trim(jsonString); // Remove the surrounding curly braces if (trimmedJson.front() == '{' && trimmedJson.back() == '}') { trimmedJson = trimmedJson.substr(1, trimmedJson.size() - 2); } else { throw runtime_error("Cannot decode JSON: "+jsonString); } stringstream ss(trimmedJson); string item; while (getline(ss, item, ',')) { size_t colonPos = item.find(':'); if (colonPos == std::string::npos) { // ignore invalide key-value pair // std::cerr << "Invalid key-value pair." << std::endl; continue; } std::string key = trim(item.substr(0, colonPos)); std::string value = trim(item.substr(colonPos + 1)); key = removeQuotes(key); // Remove surrounding quotes from key value = removeQuotes(value); // Remove surrounding quotes from value if it's a string result[key] = value; } return result; } // parses an HTTP response and returns the body of the response string parseHttpResponse(const string &httpResponse) { std::istringstream responseStream(httpResponse); std::string line; // 1. Parse the Status Line std::string httpVersion; int statusCode; std::string statusMessage; // Get the first line (status line) std::getline(responseStream, line); istringstream statusLineStream(line); statusLineStream >> httpVersion >> statusCode; std::getline(statusLineStream, statusMessage); // std::cout << "HTTP Version: " << httpVersion << std::endl; // std::cout << "Status Code: " << statusCode << std::endl; // std::cout << "Status Message: " << statusMessage << std::endl; // 2. Parse Header // map<string, std::string> headers; while (std::getline(responseStream, line) && line != "\r") { // if (line.find(":") != std::string::npos) { // std::string headerName = line.substr(0, line.find(":")); // std::string headerValue = line.substr(line.find(":") + 2); // Skip the ": " characters // headers[headerName] = headerValue; // } } // std::cout << "\nHeaders:\n"; // for (const auto& header : headers) { // std::cout << header.first << ": " << header.second << std::endl; // } // 3. Parse Body (if any) string body; getline(responseStream, body, '\0'); // Read the rest of the content as the body return body; } // Courtesy of ChatGPT string url_encode(const std::string &value) { std::ostringstream escaped; escaped.fill('0'); escaped << std::hex; for (char c: value) { // Alphanumeric characters don't need to be escaped if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { escaped << c; } else { // Escape any other character escaped << '%' << std::setw(2) << (int) (unsigned char) c; } } return escaped.str(); } /** * Run a script on the server * @param script The script to request. * @return The Http response. */ string requestTTT(string script) { // cout << "Trying " +script << endl; string answer = parseHttpResponse(HttpConnect::makeRequest("agile.bu.edu", "/backend/web/" + script, "8013")); //parseHttpResponse(HttpConnect::makeRequest("localhost", "/" + script, "8080")); return answer; } int strToInt(string theStr) { try { return stoi(theStr); } catch (invalid_argument e) { return -1; } catch (out_of_range e) { return -1; } } // IMPLEMENTATIONS PLAYER_CODE newPlayer(string name) { return requestTTT("newPlayer.pl"); } string getName(PLAYER_CODE thePlayerCode) { return requestTTT("lookupCode.pl?playerCode=" + thePlayerCode); } string getPlayerStatus(PLAYER_CODE thePlayerCode) { return requestTTT("playerStatus.pl?playerCode=" + thePlayerCode); } string getTopRatings() { return requestTTT("topRatings.pl"); } GAME_CODE newGame(PLAYER_CODE xPlayerCode, PLAYER_CODE yPlayerCode) { string gameCode = requestTTT("newGame.pl"); // set X and Y players requestTTT("changeGameStatus.pl?gameCode=" + gameCode + "&setX=" + xPlayerCode + "&setY=" + yPlayerCode); return gameCode; } SQUARE getWhoToPlay(GAME_CODE theGameCode) { return requestTTT("gameSide.pl")[0]; } string getModTime(GAME_CODE theGameCode) { return requestTTT("getModeType.pl?gameCode=" + theGameCode); } string getGameStatus(GAME_CODE theGameCode) { return requestTTT("gameStatus.pl?gameCode=" + theGameCode); } map<string,string> parseGameStatus(GAME_CODE theGameCode) { return parseJson(requestTTT("gameStatus.pl?gameCode=" + theGameCode)); } string makeMove(GAME_CODE theGameCode, PLAYER_CODE thePlayerCode, SQUARE theSide, int row, int col) { return requestTTT("changeGameStatus.pl?gameCode=" + theGameCode + "&" + (theSide == 'x' ? "makeMoveX" : "makeMoveY") + "&playerCode=" + thePlayerCode + "&row=" + to_string(row) + "&col=" + to_string(col) ); } int getRows(GAME_CODE theGameCode) { return strToInt(parseGameStatus(theGameCode)["rows"]); } int getCols(GAME_CODE theGameCode) { return strToInt(parseGameStatus(theGameCode)["cols"]); } string getBoard(GAME_CODE theGameCode) { return parseGameStatus(theGameCode)["board"]; } SQUARE getHasWon(GAME_CODE theGameCode) { return parseGameStatus(theGameCode)["hasWon"][0]; } SQUARE getToMove(GAME_CODE theGameCode) { return parseGameStatus(theGameCode)["toMove"][0]; } No newline at end of file ttt_interface/ttt.h 0 → 100644 +129 −0 Original line number Diff line number Diff line // // Created by Ari on 10/1/24. // #include <iostream> using namespace std; #ifndef HW3_STAFF_TTT_H #define HW3_STAFF_TTT_H // various types. using PLAYER_CODE = string; // represents the code of a player using GAME_CODE = string; // represents the code of a game using SQUARE = char; // 'x', 'y', '-' or '*' // PLAYER functions /** * Creates a new player with name [name]. * @param name The name of the new player. * @return A code for the new player. */ PLAYER_CODE newPlayer(string name); /** * @param thePlayerCode The code for the player in question. * @return The name associated with code [thePlayerCode]. */ string getName(PLAYER_CODE thePlayerCode); /** * @param thePlayerCode The code for the player in question. * @return Status information about the player with code [thePlayerCode] in JSON format. * @see https://en.wikipedia.org/wiki/JSON - a description of JSON * @see https://www.w3schools.com/whatis/whatis_json.asp - descriptions through examples */ string getPlayerStatus(PLAYER_CODE thePlayerCode); /** * @return A human readable list of the top players in the system. */ string getTopRatings(); // GAME FUNCTIONS /** * Creates a new game. * @param xPlayerCode The code of the player playing for 'x'. * @param yPlayerCode The code of the player playing for 'y'. * @return a code for the new game. */ GAME_CODE newGame(PLAYER_CODE xPlayerCode, PLAYER_CODE yPlayerCode); /** * @param theGameCode The code of the Game in question. * @return The side that is currently set to play in the game with code [theGameCode]. */ SQUARE getWhoToPlay(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return How many of the same-type square in a row are needed to win. */ int getInARow(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The date-time when the game with code [theGameCode] was last modified. */ string getModTime(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The current status of the game with code [theGameCode] in JSON format. * @see https://en.wikipedia.org/wiki/JSON - a description of JSON * @see https://www.w3schools.com/whatis/whatis_json.asp - descriptions through examples */ string getGameStatus(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The number of rows on the board of the current game. */ int getRows(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The number of columns on the board of the game with the given game code. */ int getCols(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The next player to move in the game with the given game code. */ SQUARE getToMove(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return A tstring representing the current board in the game with the given game code. */ string getBoard(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return Who has won the game, or '-' if no one has won yet. */ SQUARE getHasWon(GAME_CODE theGameCode); /** * Makes a move for side [side] by the player with code [thePlayerCode] * at row [row] and column [col] of the board for the game with * code [theGameCode]. * @param theGameCode The code of the game being played. * @param thePlayerCode The code of the player making the move. * @param theSize The side that is playing. * @param row The row at which the move is made, starting at 0. * @param col The column at which the move is made, starting at 0. * @return a description of an error, if an error occurred (and an empty string otherwise). * Errors include playing out of turn, playing for the wrong side, * or playing to an occupied square, among others. */ string makeMove(GAME_CODE theGameCode, PLAYER_CODE thePlayerCode, SQUARE theSide, int row, int col); #endif //HW3_STAFF_TTT_H Loading
ttt_interface/HttpConnect.cpp 0 → 100644 +70 −0 Original line number Diff line number Diff line // // Created by Ari on 10/1/24. // #include "HttpConnect.h" #include <iostream> #include <string> #include <cstring> #include <unistd.h> #include <netdb.h> #include <sys/socket.h> #include <arpa/inet.h> using namespace std; string HttpConnect::makeRequest(string host, string path, string port) { // Step 1: Create a socket int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { throw new HttpConnect::ConnectionError("Failed to create socket"); } // Step 2: Resolve hostname to an IP address struct addrinfo hints, *res; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; // IPv4 hints.ai_socktype = SOCK_STREAM; // TCP if (getaddrinfo(host.c_str(), port.c_str(), &hints, &res) != 0) { close(sock); throw new HttpConnect::ConnectionError("Failed to resolve hostname"); } // Step 3: Connect to the server if (connect(sock, res->ai_addr, res->ai_addrlen) != 0) { close(sock); throw new HttpConnect::ConnectionError("Failed to connect to server"); } freeaddrinfo(res); // Free memory that is no longer needed after connecting // Step 4: Send HTTP GET request std::string request = "GET " + path + " HTTP/1.1\r\n" "Host: " + host + "\r\n" "Connection: close\r\n\r\n"; if (send(sock, request.c_str(), request.size(), 0) == -1) { close(sock); throw new HttpConnect::ConnectionError("Failed to send request"); } // Step 5: Receive and print the response const int buffer_size = 4096; char buffer[buffer_size]; std::string response; ssize_t bytesReceived; while ((bytesReceived = recv(sock, buffer, buffer_size - 1, 0)) > 0) { buffer[bytesReceived] = '\0'; // Null-terminate the buffer response.append(buffer); } if (bytesReceived < 0) { close(sock); throw new HttpConnect::ConnectionError("Error receiving response"); } else { close(sock); return response; } } No newline at end of file
ttt_interface/HttpConnect.h 0 → 100644 +30 −0 Original line number Diff line number Diff line // // Created by Ari Trachtenberg on 10/1/24, based on ChatGPT. // #include <iostream> using namespace std; #ifndef HW3_STAFF_HTTPCONNECT_H #define HW3_STAFF_HTTPCONNECT_H class HttpConnect { public: // METHODS /** * Makes a request from https://[host]:[port]/[path] and returns the response. * @param host The host to which to connect. * @param port The port on that host to which to connect. * @param path The path to request on that host. * @return The response to the query. * @throws ConnectionError upon an error. */ static string makeRequest(string host, string path, string port = "80"); // SUBCLASSES class ConnectionError:public runtime_error { public: ConnectionError(string err): runtime_error(err) {} }; }; #endif //HW3_STAFF_HTTPCONNECT_H
ttt_interface/ttt.cpp 0 → 100644 +216 −0 Original line number Diff line number Diff line // // Created by Ari on 10/1/24. // #include <iostream> #include <iomanip> #include <sstream> #include <string> #include <map> #include "HttpConnect.h" #include "ttt.h" // HELPERS - mostly by ChatGPT // trim whitespace std::string trim(const std::string& str) { size_t start = str.find_first_not_of(" \t\n\r\f\v"); size_t end = str.find_last_not_of(" \t\n\r\f\v"); return (start == std::string::npos || end == std::string::npos) ? "" : str.substr(start, end - start + 1); } // Function to remove surrounding quotes from a string std::string removeQuotes(const std::string& str) { if (str.front() == '"' && str.back() == '"') { return str.substr(1, str.size() - 2); } return str; } // Basic JSON parser for flat key-value pairs map<string, string> parseJson(const std::string& jsonString) { map<string, string> result; string trimmedJson = trim(jsonString); // Remove the surrounding curly braces if (trimmedJson.front() == '{' && trimmedJson.back() == '}') { trimmedJson = trimmedJson.substr(1, trimmedJson.size() - 2); } else { throw runtime_error("Cannot decode JSON: "+jsonString); } stringstream ss(trimmedJson); string item; while (getline(ss, item, ',')) { size_t colonPos = item.find(':'); if (colonPos == std::string::npos) { // ignore invalide key-value pair // std::cerr << "Invalid key-value pair." << std::endl; continue; } std::string key = trim(item.substr(0, colonPos)); std::string value = trim(item.substr(colonPos + 1)); key = removeQuotes(key); // Remove surrounding quotes from key value = removeQuotes(value); // Remove surrounding quotes from value if it's a string result[key] = value; } return result; } // parses an HTTP response and returns the body of the response string parseHttpResponse(const string &httpResponse) { std::istringstream responseStream(httpResponse); std::string line; // 1. Parse the Status Line std::string httpVersion; int statusCode; std::string statusMessage; // Get the first line (status line) std::getline(responseStream, line); istringstream statusLineStream(line); statusLineStream >> httpVersion >> statusCode; std::getline(statusLineStream, statusMessage); // std::cout << "HTTP Version: " << httpVersion << std::endl; // std::cout << "Status Code: " << statusCode << std::endl; // std::cout << "Status Message: " << statusMessage << std::endl; // 2. Parse Header // map<string, std::string> headers; while (std::getline(responseStream, line) && line != "\r") { // if (line.find(":") != std::string::npos) { // std::string headerName = line.substr(0, line.find(":")); // std::string headerValue = line.substr(line.find(":") + 2); // Skip the ": " characters // headers[headerName] = headerValue; // } } // std::cout << "\nHeaders:\n"; // for (const auto& header : headers) { // std::cout << header.first << ": " << header.second << std::endl; // } // 3. Parse Body (if any) string body; getline(responseStream, body, '\0'); // Read the rest of the content as the body return body; } // Courtesy of ChatGPT string url_encode(const std::string &value) { std::ostringstream escaped; escaped.fill('0'); escaped << std::hex; for (char c: value) { // Alphanumeric characters don't need to be escaped if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { escaped << c; } else { // Escape any other character escaped << '%' << std::setw(2) << (int) (unsigned char) c; } } return escaped.str(); } /** * Run a script on the server * @param script The script to request. * @return The Http response. */ string requestTTT(string script) { // cout << "Trying " +script << endl; string answer = parseHttpResponse(HttpConnect::makeRequest("agile.bu.edu", "/backend/web/" + script, "8013")); //parseHttpResponse(HttpConnect::makeRequest("localhost", "/" + script, "8080")); return answer; } int strToInt(string theStr) { try { return stoi(theStr); } catch (invalid_argument e) { return -1; } catch (out_of_range e) { return -1; } } // IMPLEMENTATIONS PLAYER_CODE newPlayer(string name) { return requestTTT("newPlayer.pl"); } string getName(PLAYER_CODE thePlayerCode) { return requestTTT("lookupCode.pl?playerCode=" + thePlayerCode); } string getPlayerStatus(PLAYER_CODE thePlayerCode) { return requestTTT("playerStatus.pl?playerCode=" + thePlayerCode); } string getTopRatings() { return requestTTT("topRatings.pl"); } GAME_CODE newGame(PLAYER_CODE xPlayerCode, PLAYER_CODE yPlayerCode) { string gameCode = requestTTT("newGame.pl"); // set X and Y players requestTTT("changeGameStatus.pl?gameCode=" + gameCode + "&setX=" + xPlayerCode + "&setY=" + yPlayerCode); return gameCode; } SQUARE getWhoToPlay(GAME_CODE theGameCode) { return requestTTT("gameSide.pl")[0]; } string getModTime(GAME_CODE theGameCode) { return requestTTT("getModeType.pl?gameCode=" + theGameCode); } string getGameStatus(GAME_CODE theGameCode) { return requestTTT("gameStatus.pl?gameCode=" + theGameCode); } map<string,string> parseGameStatus(GAME_CODE theGameCode) { return parseJson(requestTTT("gameStatus.pl?gameCode=" + theGameCode)); } string makeMove(GAME_CODE theGameCode, PLAYER_CODE thePlayerCode, SQUARE theSide, int row, int col) { return requestTTT("changeGameStatus.pl?gameCode=" + theGameCode + "&" + (theSide == 'x' ? "makeMoveX" : "makeMoveY") + "&playerCode=" + thePlayerCode + "&row=" + to_string(row) + "&col=" + to_string(col) ); } int getRows(GAME_CODE theGameCode) { return strToInt(parseGameStatus(theGameCode)["rows"]); } int getCols(GAME_CODE theGameCode) { return strToInt(parseGameStatus(theGameCode)["cols"]); } string getBoard(GAME_CODE theGameCode) { return parseGameStatus(theGameCode)["board"]; } SQUARE getHasWon(GAME_CODE theGameCode) { return parseGameStatus(theGameCode)["hasWon"][0]; } SQUARE getToMove(GAME_CODE theGameCode) { return parseGameStatus(theGameCode)["toMove"][0]; } No newline at end of file
ttt_interface/ttt.h 0 → 100644 +129 −0 Original line number Diff line number Diff line // // Created by Ari on 10/1/24. // #include <iostream> using namespace std; #ifndef HW3_STAFF_TTT_H #define HW3_STAFF_TTT_H // various types. using PLAYER_CODE = string; // represents the code of a player using GAME_CODE = string; // represents the code of a game using SQUARE = char; // 'x', 'y', '-' or '*' // PLAYER functions /** * Creates a new player with name [name]. * @param name The name of the new player. * @return A code for the new player. */ PLAYER_CODE newPlayer(string name); /** * @param thePlayerCode The code for the player in question. * @return The name associated with code [thePlayerCode]. */ string getName(PLAYER_CODE thePlayerCode); /** * @param thePlayerCode The code for the player in question. * @return Status information about the player with code [thePlayerCode] in JSON format. * @see https://en.wikipedia.org/wiki/JSON - a description of JSON * @see https://www.w3schools.com/whatis/whatis_json.asp - descriptions through examples */ string getPlayerStatus(PLAYER_CODE thePlayerCode); /** * @return A human readable list of the top players in the system. */ string getTopRatings(); // GAME FUNCTIONS /** * Creates a new game. * @param xPlayerCode The code of the player playing for 'x'. * @param yPlayerCode The code of the player playing for 'y'. * @return a code for the new game. */ GAME_CODE newGame(PLAYER_CODE xPlayerCode, PLAYER_CODE yPlayerCode); /** * @param theGameCode The code of the Game in question. * @return The side that is currently set to play in the game with code [theGameCode]. */ SQUARE getWhoToPlay(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return How many of the same-type square in a row are needed to win. */ int getInARow(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The date-time when the game with code [theGameCode] was last modified. */ string getModTime(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The current status of the game with code [theGameCode] in JSON format. * @see https://en.wikipedia.org/wiki/JSON - a description of JSON * @see https://www.w3schools.com/whatis/whatis_json.asp - descriptions through examples */ string getGameStatus(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The number of rows on the board of the current game. */ int getRows(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The number of columns on the board of the game with the given game code. */ int getCols(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return The next player to move in the game with the given game code. */ SQUARE getToMove(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return A tstring representing the current board in the game with the given game code. */ string getBoard(GAME_CODE theGameCode); /** * @param theGameCode The code of the Game in question. * @return Who has won the game, or '-' if no one has won yet. */ SQUARE getHasWon(GAME_CODE theGameCode); /** * Makes a move for side [side] by the player with code [thePlayerCode] * at row [row] and column [col] of the board for the game with * code [theGameCode]. * @param theGameCode The code of the game being played. * @param thePlayerCode The code of the player making the move. * @param theSize The side that is playing. * @param row The row at which the move is made, starting at 0. * @param col The column at which the move is made, starting at 0. * @return a description of an error, if an error occurred (and an empty string otherwise). * Errors include playing out of turn, playing for the wrong side, * or playing to an occupied square, among others. */ string makeMove(GAME_CODE theGameCode, PLAYER_CODE thePlayerCode, SQUARE theSide, int row, int col); #endif //HW3_STAFF_TTT_H