Ok so this is what is needed from this assignment:
1. Implement the send() member function that is declared within the NoughtsAndCrosses class. This function should transmit the whole NoughtsAndCrosses object to the opponent (20%)
2. Add appropriate code to the main() function to allow the game to be played over the network (some of this has been done for you). After each turn the Dump member function should be invoked in order to display the current games state. (30%)
3. Derive a new class named BitNoughtsAndCrosses that transmits the current state of the board, using the individual bits within the two integer variables declared within the GameData structure. Embed pre-processor directives within both client and server projects to separate the code that implements the game using the BitNoughtsAndCrosses, from that of the solution to task 2. (50%)
Tasks 1 and 2 were completed in 30 minutes, its the last one thats giving me hassle. The pre-processor directives are simple to implement, its understanding the packing, sending and unpacking of the integers and then somehow getting that info onto the board.
Here is my up to date code:
Server:
- Code: Select all
#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <ctime>
#include <math.h>
#include <vector>
using namespace std;
#define BITWISEGAME 1
// Noughts and Crosses (Tic Tac Toe) game
class NoughtsAndCrosses
{
protected:
// An array of integers holding the bits
// 3 by 3 board is represented as a one dimensional array
char board[9];
// Players symbols are either X or O
char playerSymbol;
char aiSymbol;
// Game state
bool playerWin, aiWin, draw;
// If there is a winner or a draw update the state
bool CheckWin(char symbol)
{
bool won = false;
// Is there a winner?
// Check horizontal
if (board[0] == symbol && board[1] == symbol && board[2] == symbol) won = true;
if (board[3] == symbol && board[4] == symbol && board[5] == symbol) won = true;
if (board[6] == symbol && board[7] == symbol && board[8] == symbol) won = true;
// Check vertical
if (board[0] == symbol && board[3] == symbol && board[6] == symbol) won = true;
if (board[1] == symbol && board[4] == symbol && board[7] == symbol) won = true;
if (board[2] == symbol && board[5] == symbol && board[8] == symbol) won = true;
// Check diagonals
if (board[0] == symbol && board[4] == symbol && board[8] == symbol) won = true;
if (board[2] == symbol && board[4] == symbol && board[6] == symbol) won = true;
// If there is a winner who won?
if (won){
if (symbol == aiSymbol) aiWin = true;
else playerWin = true;
return true;
}
// If no one has won then check to see if it is a draw
for(int n=0;n<9;n++)
if (board[n] == ' ') return false;
draw = true;
return true;
}
public:
NoughtsAndCrosses()
{
for(int n=0;n<9;n++){
board[n] = ' ';
}
playerSymbol = 'X';
aiSymbol = 'O';
playerWin = aiWin = draw = false;
}
bool IsFinished()
{
if (playerWin || aiWin || draw) return true;
else return false;
}
void DisplayWinner()
{
if (playerWin)
cout << "\n The Player has won \n";
else if (aiWin)
cout << "\n The AI has won \n";
else
cout << "\n Its a draw \n";
}
bool Play(char symbol, int pos)
{
// Ensure the position is free
if(board[pos]== ' '){
board[pos] = symbol;
CheckWin(symbol);
return true;
}
else return false;
}
void AIPlay()
{
srand((unsigned)time(0));
int index;
do{
index = rand();
index = index % 9;
}
while(! Play('O', index));
}
void Dump()
{
cout << board[0] << " | " << board[1] << " | " << board[2] << "\n";
cout << "--------\n";
cout << board[3] << " | " << board[4] << " | " << board[5] << "\n";
cout << "--------\n";
cout << board[6] << " | " << board[7] << " | " << board[8] << "\n";
}
// Transmit the whole object to the opponent
void Send(SOCKET s)
{
// Create an array that can hold the object
char sendObject[sizeof(NoughtsAndCrosses)];
// Copy the object into an array
memcpy(sendObject, this, sizeof(NoughtsAndCrosses));
// Invoke send passing it the socket etc
send(s, sendObject, sizeof(NoughtsAndCrosses), 0);
}
};
// Contains game data to be transmitted
struct GameData
{
int playerData, aiData;
};
// Derived class to transmit bits
class BitNoughtsAndCrosses : public NoughtsAndCrosses{
public:
// Create an object to access the struct
GameData myGame;
// Create my BITS array
int bits[9];
BitNoughtsAndCrosses()
{
myGame.aiData = 0;
myGame.playerData = 0;
// initialise my BITS array
int myBits = 1;
for (int i = 0; i < 9; i++)
{
if (i == 0) bits[i] = myBits;
else bits[i] = myBits << 1 * i;
}
}
// Pack my data
void compress()
{
// Check each element of the board then compresses the data
for (int i = 0; i < 9; i++)
{
switch (board[i])
{
case ' ': myGame.aiData |= 0; myGame.playerData |= 0;break;
case 'X': myGame.aiData |= (bits[i] << 8); myGame.playerData |= (bits[i] << 8);break;
case 'O': myGame.aiData |= (bits[i+1] << 7); myGame.playerData |= (bits[i+1] << 7);break;
}
}
//cout << myGame.aiData << endl;
//cout << myGame.playerData << endl;
}
void Send(SOCKET s)
{
// create an array that can hold the object
char sendStruct[sizeof(GameData)];
// Copy the object into an array
memcpy(sendStruct, (void*)(&myGame), sizeof(GameData));
// Invoke send
send(s, sendStruct , sizeof(GameData), 0);
}
void unCompress()
{
// Check each element of the board
for (int i = 0; i < 9; i++)
{
switch (board[i])
{
case ' ': myGame.aiData &= 0; myGame.playerData &= 0;break;
case 'X': myGame.aiData &= (bits[i] >> 8); myGame.playerData &= (bits[i] >> 8);break;
case 'O': myGame.aiData &= (bits[i] >> 7); myGame.playerData &= (bits[i] >> 7);break;
}
}
}
};
int main(int argc, char* argv[])
{
SOCKADDR_STORAGE from;
int fromlen, retval, socket_type, bytesRecv;
char servstr[NI_MAXSERV], hoststr[NI_MAXHOST], startBuffer[50];
SOCKET serverSocket, acceptSocket;
int port = 55555;
WSADATA wsaData;
int wsaerr;
WORD wVersionRequested = MAKEWORD(2,2);
wsaerr = WSAStartup(wVersionRequested, &wsaData);
// Load the DLL
if (wsaerr != 0){
cout << "The winsock dll not found!" << endl;
return 0;
} else {
cout << "The winsock dll found!" << endl;
cout << "The status: "<< wsaData.szSystemStatus << endl;
}
// Create a socket
serverSocket = INVALID_SOCKET;
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET){
cout << "Error at socket(): " << WSAGetLastError() << endl;
WSACleanup();
return 0;
} else {
cout << "Socket() is ok!" << endl;
}
// Bind the socket
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(port);
if (bind(serverSocket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR){
cout << "bind() failed: " << WSAGetLastError() << endl;
closesocket(serverSocket);
WSACleanup();
return 0;
} else {
cout << "bind() is OK!" << endl;
}
// Listen for a new connection
if (listen(serverSocket, 1) == SOCKET_ERROR){
cout << "Listen(): Error listening on socket " << WSAGetLastError() << endl;
} else {
cout << "Listen() is ok, I'm waiting for connections..." << endl;
}
// Accept the connection
fromlen = sizeof(socket_type);
retval = getsockopt(serverSocket, SOL_SOCKET, SO_TYPE, (char*)&socket_type, &fromlen);
fromlen = sizeof(from);
acceptSocket = accept(serverSocket, (SOCKADDR*)&from, &fromlen);
if (acceptSocket == INVALID_SOCKET){
cout << "accept failed: " << WSAGetLastError() << endl;
WSACleanup();
return -1;
}
retval = getnameinfo((SOCKADDR*)&from, fromlen, hoststr, NI_MAXHOST, servstr, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
if (retval != 0){
cout << "getnameinfo failed: " << retval << endl;
WSACleanup();
return -1;
}
cout << "Accepted connection from host " << hoststr << " and port " << servstr << endl;
cout << "Accepted connection" << endl;
// Receive the start game message
if (acceptSocket == INVALID_SOCKET){
cout << "Accept Failed!" << endl;
}
bytesRecv = recv(acceptSocket, startBuffer, 50, 0);
if (bytesRecv == SOCKET_ERROR){
cout << "Server: recv() error";
}
cout << startBuffer << endl;
// Define an array to hold the object received
char buffer[sizeof(NoughtsAndCrosses)];
char bitBuffer[sizeof(GameData)];
NoughtsAndCrosses *tictactoe = new NoughtsAndCrosses();
BitNoughtsAndCrosses *theGame = new BitNoughtsAndCrosses();
// while game is not finished
while(!(tictactoe->IsFinished())){
tictactoe->AIPlay();
tictactoe->Dump();
//theGame->compress();
tictactoe->Send(acceptSocket);
//theGame->Send(acceptSocket);
// if game not finished
if(!(tictactoe->IsFinished()))
{
//theGame->unCompress();
bytesRecv = recv(acceptSocket, buffer, sizeof(NoughtsAndCrosses), 0);
//bytesRecv = recv(acceptSocket, bitBuffer, sizeof(GameData), 0);
memcpy(tictactoe, buffer, sizeof(NoughtsAndCrosses));
//memcpy(theGame, bitBuffer, sizeof(GameData));
tictactoe->Dump();
}
}
tictactoe->DisplayWinner();
system("PAUSE");
WSACleanup();
return 0;
}
Client:
- Code: Select all
#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>
#include <iostream>
#include <ctime>
#include <math.h>
using namespace std;
// Noughts and Crosses (Tic Tack Toe) game
class NoughtsAndCrosses{
protected:
// 3 by 3 board is represented as a one dimensional array
char board[9];
// Players symbols are either X or O
char playerSymbol;
char aiSymbol;
// Game state
bool playerWin,aiWin,draw;
// If there is a winner or a draw update the state
bool CheckWin(char symbol){
bool won = false;
// Is there a winner?
// Check horizontal
if (board[0] == symbol && board[1] == symbol && board[2] == symbol) won = true;
if (board[3] == symbol && board[4] == symbol && board[5] == symbol) won = true;
if (board[6] == symbol && board[7] == symbol && board[8] == symbol) won = true;
// Check vertical
if (board[0] == symbol && board[3] == symbol && board[6] == symbol) won = true;
if (board[1] == symbol && board[4] == symbol && board[7] == symbol) won = true;
if (board[2] == symbol && board[5] == symbol && board[8] == symbol) won = true;
// Check diagonals
if (board[0] == symbol && board[4] == symbol && board[8] == symbol) won = true;
if (board[2] == symbol && board[4] == symbol && board[6] == symbol) won = true;
// If there is a winner who won?
if (won){
if (symbol == aiSymbol) aiWin = true;
else playerWin = true;
return true;
}
// If no one has won then check to see if it is a draw
for(int n=0;n<9;n++)
if (board[n] == ' ') return false;
draw = true;
return true;
}
public:
NoughtsAndCrosses(){
for(int n=0;n<9;n++)
board[n] = ' ';
playerSymbol = 'X';
aiSymbol = 'O';
playerWin = aiWin = draw = false;
}
bool IsFinished(){
if (playerWin || aiWin || draw) return true;
else return false;
}
void DisplayWinner(){
if (playerWin)
cout << "\n The Player has won \n";
else if (aiWin)
cout << "\n The AI has won \n";
else
cout << "\n Its a draw \n";
}
bool Play(char symbol, int pos){
// Ensure the position is free
if(board[pos]== ' '){
board[pos] = symbol;
CheckWin(symbol);
return true;
}
else return false;
}
void AIPlay(){
srand((unsigned)time(0));
int index;
do{
index = rand();
index = index % 9;
}
while(! Play('O', index));
}
void Dump(){
cout << board[0] << " | " << board[1] << " | " << board[2] << "\n";
cout << "--------\n";
cout << board[3] << " | " << board[4] << " | " << board[5] << "\n";
cout << "--------\n";
cout << board[6] << " | " << board[7] << " | " << board[8] << "\n";
}
// Transmit the whole object to the opponent
void Send(SOCKET s){
// Define a character array that is large enough to hold the object
char sendObject[sizeof(NoughtsAndCrosses)];
// Copy the object into the character array
memcpy(sendObject, this, sizeof(NoughtsAndCrosses));
// Invoke send
send(s,sendObject, sizeof(NoughtsAndCrosses),0);
}
};
// Contains game data to be transmitted
struct GameData
{
int playerData,aiData;
};
class BitNoughtsAndCrosses : public NoughtsAndCrosses{
public:
// Create an object to access the struct
GameData myGame;
// Setup bit constants
int bits[9];
BitNoughtsAndCrosses()
{
// Give each integer a 0 bit value
myGame.aiData = 0;
myGame.playerData = 0;
// initialise my BITS array
int myBits = 1;
for (int i = 0; i < 9; i++)
{
if (i == 0) bits[i] = myBits;
else bits[i] = myBits << 1 * i;
}
}
void compress()
{
// Check each element of the board
for (int i = 0; i < 9; i++)
{
switch (board[i])
{
case ' ': myGame.aiData |= 0; myGame.playerData |= 0;break;
case 'X': myGame.aiData |= (bits[i] << 8); myGame.playerData |= (bits[i] << 8);break;
case 'O': myGame.aiData |= (bits[i+1] << 7); myGame.playerData |= (bits[i+1] << 7);break;
}
}
//cout << myGame.aiData << endl;
//cout << myGame.playerData << endl;
};
void Send(SOCKET s)
{
// create an array that can hold the object
char sendStruct[sizeof(GameData)];
// Copy the object into an array
memcpy(sendStruct, (void*)(&myGame), sizeof(GameData));
// Invoke send
send(s, sendStruct , sizeof(GameData), 0);
}
void unCompress()
{
// Check each element of the board
for (int i = 0; i < 9; i++)
{
switch (board[i])
{
case ' ': myGame.aiData &= 0; myGame.playerData &= 0;break;
case 'X': myGame.aiData &= (bits[i] >> 8); myGame.playerData &= (bits[i] >> 8);break;
case 'O': myGame.aiData &= (bits[i] >> 7); myGame.playerData &= (bits[i] >> 7);break;
}
}
}
};
int main(int argc, char* argv[]){
SOCKET clientSocket;
int port = 55555;
WSADATA wsaData;
int wsaerr;
WORD wVersionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0){
printf("The Winsock dll not found!\n");
return 0;
}
else{
printf("The Winsock dll found!\n");
printf("The status: %s.\n", wsaData.szSystemStatus);
}
clientSocket = INVALID_SOCKET;
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket== INVALID_SOCKET){
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
else {
printf("socket() is OK!\n");
}
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(port);
if (connect(clientSocket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR){
printf("Client: connect() - Failed to connect.\n");
WSACleanup();
return 0;
}
else {
printf("Client: connect() is OK.\n");
printf("Client: Can start sending and receiving data...\n");
}
int byteCount = SOCKET_ERROR;
char msg[50] = "Play noughts and crosses";
byteCount = send(clientSocket, msg, 50, 0);
if(byteCount == SOCKET_ERROR){
printf("Client: send() error %ld.\n", WSAGetLastError());
}
else{
printf("Client: sent %ld bytes \n", byteCount);
}
int bytesRecv, index;
char buffer[sizeof(NoughtsAndCrosses)];
char bitBuffer[sizeof(GameData)];
NoughtsAndCrosses *tictactoe = new NoughtsAndCrosses();
BitNoughtsAndCrosses *theGame = new BitNoughtsAndCrosses();
// while game is not finished
while(!(tictactoe->IsFinished())){
// receive the bits
// bytesRecv = recv(clientSocket, bitBuffer, sizeof(GameData), 0);
// theGame->unCompress();
bytesRecv = recv(clientSocket, buffer,sizeof(NoughtsAndCrosses), 0);
memcpy(tictactoe, buffer, sizeof(NoughtsAndCrosses));
//memcpy(theGame, bitBuffer, sizeof(GameData));
cout << "AI has completed its move\n";
tictactoe->Dump();
if (!(tictactoe->IsFinished()))
{
do{
cout << "Enter the index ";
cin >> index;
}
while(!tictactoe->Play('X',index));
tictactoe->Dump();
tictactoe->Send(clientSocket);
// theGame->Send(clientSocket);
}
}
tictactoe->DisplayWinner();
system("pause");
WSACleanup();
return 0;
}
Again another nudge would be greatly appreciated
many thanks
Martin