// function to test threads
// This function will run concurrently.
void* avatar(void* ptr) {

    // Initial variables
    int sockfd = 0;
    struct sockaddr_in servaddr;
    avatarInfo a = *((avatarInfo *) ptr);
    fprintf(a.pLog, "\n\nTHREAD FOR %i", a.avID);

    ///////////////////////// create socket

    //Create a socket for the client
    //If sockfd<0 there was an error in the creation of the socket
    if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) <0) {
        perror("Problem in creating the socket");
        exit(2);
    }

    //Creation of the socket
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr= inet_addr(a.ip);
    servaddr.sin_port =  htons(a.MazePort); //convert to big-endian order

    //Connection of the client to the socket
    int connected = connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    if (connected <0) {
        perror("Problem in connecting to the server");
        exit(3);
    }
    fprintf(a.pLog, "Avatar %d connected to socket: %i\n", a.avID, connected);


    //////////////////////////// send initial message

    AM_Message *ready = calloc(1, sizeof(AM_Message));
    if (!ready) {
        perror("No memory\n");
        exit(4);
    }

    ready->type = htonl(AM_AVATAR_READY);
    ready->avatar_ready.AvatarId = htonl(a.avID);

    //send ready message to server
    int sent = send(sockfd, ready, sizeof(AM_Message), 0);
    fprintf(a.pLog, "Avatar ready message sent: %i, for av %i\n", sent, a.avID);
    free(ready);
    sleep(1);

    ////////////////////////// initialize a move message and a rec message

    AM_Message *rec_message = calloc(1, sizeof(AM_Message));
    if(!rec_message) {
        perror("\nNo memory");
        exit(4);
    }

    ////////////////////////////////// listen to server

    while (1) {
        memset(rec_message, 0, sizeof(AM_Message));
        //printf("\n thread %i, socket %i", a.avID, sockfd);
        int x = recv(sockfd, rec_message, sizeof(AM_Message), 0);
        if ( x== 0) {
            //error: server terminated prematurely
            //printf("\n server error");
            return NULL;
        }

        ///////////////////////////////////////// if turnID matches avID, make a move
        if(ntohl(rec_message->type) == AM_AVATAR_TURN) {
            pthread_mutex_lock(&turn_lock);
            // if turn id is my id
            int move = -1;
            if(ntohl(rec_message->avatar_turn.TurnId) == a.avID) {
                // write board to the log
                fprintf(a.pLog, "\n\nits my turn: %i", a.avID);
                fprintf(a.pLog, "\nCurrent board:");
                XYPos pos;
                //look through the positions received from the server and add them to the Avatars, if they aren't there, or use them to update the maze based on the last move
                for(int b = 0; b < a.nAvatars; b++) {
                    pos.x = ntohl(rec_message->avatar_turn.Pos[b].x);
                    pos.y = ntohl(rec_message->avatar_turn.Pos[b].y);
                    fprintf(a.pLog, "\nPosition of avatar %i - x: %i y: %i", b,pos.x, pos.y);
                    //printf("\nCurrent position of avatar %i - x: %i y: %i", b,pos.x, pos.y);
                    //printf("\nAvatar %d: pos.x: %i, pos.y: %i, direction: %d, last_move: %d \n", b, Avatars[b].pos.x, Avatars[b].pos.y, Avatars[b].direction, Avatars[b].last_move);
                    if (Avatars[b].last_move == -1) { //if the avatar doesn't have a position yet
                        Avatars[b].pos = pos;
                        Avatars[b].last_move = M_NULL_MOVE;
                    }
                    else if (Avatars[b].last_move != M_NULL_MOVE) {
                        if ((pos.x == Avatars[b].pos.x) && (pos.y == Avatars[b].pos.y)) {
                            fprintf(a.pLog, "Avatar %d encountered a wall and did not move.", b);
                            AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 1);
                            Avatars[b].last_move = M_NULL_MOVE;
                        }
                        else {
                            fprintf(a.pLog, "Avatar %d moved successfully.", b);
                            switch(Avatars[b].last_move) {
                            case M_NORTH:
                                if (maze->maze[Avatars[b].pos.y][Avatars[b].pos.x].north_wall != 2) {
                                    AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0);
                                }
                                break;
                            case M_SOUTH:
                                if (maze->maze[Avatars[b].pos.y][Avatars[b].pos.x].south_wall != 2) {
                                    AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0);
                                }
                                break;
                            case M_EAST:
                                if (maze->maze[Avatars[b].pos.y][Avatars[b].pos.x].east_wall != 2) {
                                    AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0);
                                }
                                break;
                            case M_WEST:
                                if (maze->maze[Avatars[b].pos.y][Avatars[b].pos.x].west_wall != 2) {
                                    AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0);
                                }
                                break;
                            default:
                                AddWall(Avatars[b].pos.y, Avatars[b].pos.x, Avatars[b].last_move, 0);
                                break;
                            }
                            Avatars[b].pos = pos;
                            Avatars[b].direction = Avatars[b].last_move;
                            Avatars[b].last_move = M_NULL_MOVE;
                        }
                    }

                }

                ////////////////graphics////////////////
                //initscr();
                clear();
                raw();
                //start_color();
                create_border(maze->num_col, maze->num_row);
                draw_inside(maze);
                //draw_fakes(maze);
                int f;
                for (f = 0; f<a.nAvatars; f++) {
                    draw_avatar(2*Avatars[f].pos.y+1, 2*Avatars[f].pos.x+1);
                }
                //unsigned int microseconds;
                //microseconds = 200;
                //usleep(microseconds);
                refresh();

                /* Determine the direction of the move for the current Avatar */

                /* Avatar 0 has a fixed location - it never moves */
                if (a.avID == 0) {
                    if(!final_destination) {
                        final_destination = (XYPos *) calloc(1, sizeof(XYPos));
                        final_destination->x = Avatars[a.avID].pos.x;
                        final_destination->y = Avatars[a.avID].pos.y;
                    }
                    move = M_NULL_MOVE;
                }
                // if(!final_destination){
                //   for(int i = 0; i < a.nAvatars; i++){
                //     if (i == a.avID) continue;
                //     //if the Avatar is in the same place as another Avatar, save position as final_destination
                //     if((Avatars[i].pos.x == Avatars[a.avID].pos.x) && (Avatars[i].pos.y == Avatars[a.avID].pos.y)){
                //       final_destination = (XYPos *) calloc(1, sizeof(XYPos));
                //       final_destination->x = Avatars[a.avID].pos.x;
                //       final_destination->y = Avatars[a.avID].pos.y;
                //       move = M_NULL_MOVE;
                //       break;
                //     }
                //   }
                // }
                /* Determine the direction of the move for Avatars that aren't Avatar 0 */
                //if Avatar is at final_destination, it should not move
                if((final_destination) && (Avatars[a.avID].pos.x == final_destination->x) && (Avatars[a.avID].pos.y == final_destination ->y)) {
                    move = M_NULL_MOVE;
                }
                else { //if the Avatar is alone, use the rightHandRule to determine the next move
                    move = rightHandRule(Avatars[a.avID]);
                }

                //temporary fix to diagnose the initial -1 rightHandRule return
                if(move == -1) {
                    ClearFakeWalls(Avatars[a.avID].pos.y, Avatars[a.avID].pos.x);
                    move = rightHandRule(Avatars[a.avID]);
                    move = (move == -1) ? M_NULL_MOVE : move;
                }
                Avatars[a.avID].last_move = move;
                //int move = rand() % 4;
                // write move to the log
                fprintf(a.pLog, "\nMove: %i", move);
                //printf("\nMove: %i", move);

                //send a move message for the current avatar
                AM_Message *ready = calloc(1, sizeof(AM_Message));
                if (!ready) {
                    perror("No memory\n");
                    exit(4);
                }
                ready->type = htonl(AM_AVATAR_MOVE);
                ready->avatar_move.AvatarId = htonl(a.avID);
                ready->avatar_move.Direction =htonl(move);

                //send ready message to server
                int sent = send(sockfd, ready, sizeof(AM_Message), 0);
                fprintf(a.pLog, "\nAvatar move message sent: %i, for av %i", sent, a.avID);
                free(ready);
                //sleep(1);
            }
            pthread_mutex_unlock(&turn_lock);
        }

        // else if the message is success, break
        else if(ntohl(rec_message->type) == AM_MAZE_SOLVED) {
            pthread_mutex_lock(&solved_lock);
            if(!thread_return) {
                time_t myTime;
                char buff[100];
                thread_return = (char *) calloc(100, sizeof(char));
                myTime = time(NULL);
                strftime(buff, 100, "%a %d %Y, %H:%M", localtime(&myTime));
                //printf("%s\n", buff);
                sprintf(thread_return, "\nMaze Solved on %s!\n", buff);
                //printf("\nSolved!\n");
                //free(rec_message);
                //free(ptr);
            }

            //stop at solution, wait for an input to end graphics
            //refresh();
            //sleep(1);
            //clear();
            //printw("Maze solved!");
            //getch();
            //clear();
            //endwin();
            //delwin(stdscr);

            if(a.avID == 0) {
                //stop at solution, wait for an input to end graphics
                refresh();
                sleep(1);
                clear();
                printw("Maze solved!");
                getch();
                clear();
                //endwin();
            }
            pthread_mutex_unlock(&solved_lock);
            break;
        }

        else if(ntohl(rec_message->type) == AM_TOO_MANY_MOVES) {
            pthread_mutex_lock(&too_many_moves_lock);
            printf("\nToo many moves! You lose.\n");
            //fprintf(a.pLog,"\nToo many moves! You lose.\n");
            thread_return = "\nToo many moves! You lose.\n";
            //free(rec_message);
            //free(ptr);
            pthread_mutex_unlock(&too_many_moves_lock);
            break;
        }

        else if(IS_AM_ERROR(ntohl(rec_message->type))) {
            pthread_mutex_lock(&error_lock);
            thread_return = (char *) calloc(100, sizeof(char));
            printf("\nReceived Error code\n");
            sprintf(thread_return, "\nReceived Error code: %u\n", ntohl(rec_message->type));
            //free(rec_message);
            //free(ptr);
            pthread_mutex_unlock(&error_lock);
            break;
        }
    }
    //CleanupMaze();
    free(rec_message);
    free(ptr);
    pthread_exit(thread_return);
}
/* move
 * 
 * @param id - The ID number of the avatar we want to move
 * @param out_socket - The socket we are writing to
 * @param fileName - The name of the log file
 * @param nAvs - The number of avatars
 *
 * Return: Returns failure for various errors, success when all the avatars
 * find each other. 
 *
 * Psuedocode:
 * 1. Initalize variables by setting up positions, directions, moves, etc.
 * 2. Enter move loop - keep moving until all the avatars find each other
 * 3. Error checking within the loop for connection or errors from the server
 * 4. The avatars have left hand move, the masters have right hand move, if a
 * master finds an avatar, then the avatar will move with the master and also 
 * use right hand rule. 
 * 5. Free memory
 * 6. Error checking 
 */
int move(int id, int out_socket, char *fileName, int nAvs, int height, int width)
{
    int res;                        // Check connection
    AM_Message move;                // The move mesasge you get from the server
    AM_Message next_move;           // The move message you send to the server
    int move_num;                   // The number of moves we've tried
    int direction;                  // The direction we are facing
    int moving_right;               // 1: avatar using right hand rule
    int seen_avatar;                // 0: haven't found
    XYPos *curr;                    // current position
    XYPos *prev;                    // previous position
    XYPos *M_curr;                  // current master position
    XYPos *M_prev;                  // previous master position           
    int moves_attempted;            // number of moves tried in one position
    int M_moves_attempted;          // number of masters tried by master
    int M_direction;                // direction master is facing
    int total_moves;                // tracks how many moves we made

    // ID 0 is always master
    if(id == 0) {
        moving_right = 1; // master is always moving right
    }

    // set up current and previous positions
    total_moves = 0;                
    move_num = 0;
    direction = 0;
    moving_right = 0;
    seen_avatar = 0;
    curr = calloc(1, sizeof(XYPos));
    prev = calloc(1, sizeof(XYPos));
    prev->x = -1;
    prev->y = -1;
    curr->x = -1;
    curr->y = -1;
    moves_attempted = 0;

    M_prev = calloc(1, sizeof(XYPos));
    M_prev->x = 0;
    M_prev->y = 0;
    M_moves_attempted = 0;
    M_direction = 0;

    for(;;) {

        memset(&next_move, 0, sizeof(next_move));
        res = recv(out_socket, &move, sizeof(move), 0);

        // check connection
        if(res == 0) {
            break;
        }
    
        // check message for error
        if (IS_AM_ERROR(ntohl(move.type))) {
            break;
        }

        // if success, we solved it!
        if(ntohl(move.type) == AM_MAZE_SOLVED) {
            break;
        }

        // if we met the master, start moving right
        if(ntohl(curr->x) == ntohl(move.avatar_turn.Pos[0].x) && ntohl(curr->y) == ntohl(move.avatar_turn.Pos[0].y)) {
                moving_right = 1;
        }
        
        if(ntohl(move.avatar_turn.TurnId) == 0) {
            // tracking the master, on the master's turn.
            M_curr = &(move.avatar_turn.Pos[0]); 
            if(ntohl(M_prev->x) != ntohl(M_curr->x) || ntohl(M_prev->y) != ntohl(M_curr->y)) {
                M_moves_attempted = 0;
                M_direction = getDirectionChange(M_prev, M_curr);
            }
            else {
                M_moves_attempted++;
            }

            M_prev->x = M_curr->x;
            M_prev->y = M_curr->y;
        }
        
        // if it's not our turn, don't worry.
        if(ntohl(move.avatar_turn.TurnId) != id) {
            continue;
        }

        // get the current location
        curr = &(move.avatar_turn.Pos[id]);

        // set up our next move
        next_move.type = htonl(AM_AVATAR_MOVE);
        next_move.avatar_move.AvatarId = htonl(id);

        // check if we moved, and if so, reset direction
        if(ntohl(prev->x) != ntohl(curr->x) || ntohl(prev->y) != ntohl(curr->y)) {
            moves_attempted = 0;
            direction = getDirectionChange(prev, curr);
        }
        else {
            moves_attempted++;
        }

        // get next move for left hand
        move_num = getNextMoveL(direction, moves_attempted);

        // update our previous pointer
        prev->x = curr->x;
        prev->y = curr->y;

        // if we are moving right, overwrite the left hand with right hand
        if(moving_right) {
            move_num = getNextMoveR(M_direction, M_moves_attempted);
        }

        // testing, print information about yourself
        //printf("%i, %i, %i, %i\n", id, direction, ntohl(curr->x), ntohl(curr->y));
        //fflush(stdout);

        if(!seen_avatar && moving_right) {
            seen_avatar = 1;
            move_num = 8;
        }

        // set direction and move
        total_moves++;
        next_move.avatar_move.Direction = htonl(move_num);
        send(out_socket, &next_move, sizeof(next_move), 0);
    }

    // free our dynamically allocated memory
    free(M_prev);
    free(prev);
    
    if(res == 0) {
        fprintf(stderr, "Connection timed out!");
        return EXIT_FAILURE;
    }

    // determine why we exited the for loop.
    switch(ntohl(move.type)) {
        case AM_MAZE_SOLVED:
            if(id == 0) {
                printSuccess(fileName, move, total_moves, nAvs);
            }
            return EXIT_SUCCESS;

        case AM_TOO_MANY_MOVES:
            fprintf(stderr, "Max moves exceeded.");
            return EXIT_FAILURE;

        case AM_SERVER_DISK_QUOTA:
            fprintf(stderr, "Server disk quota reached.");
            return EXIT_FAILURE;

        case AM_SERVER_OUT_OF_MEM:
            fprintf(stderr, "Server out of memory.");
            return EXIT_FAILURE;

        default:
            fprintf(stderr, "Unknown error.");
            return EXIT_FAILURE;
    }  
}
int main(int argc, char *argv[]) {

    VERBOSE = 0;
    GRAPHICS = 0;
    validate(argc, argv);
    
    int avatarID = atoi(argv[1]);
    FILE *logFile;
    logFile = fopen(argv[6], "a+");
    char *IP = (char*)calloc(strlen(argv[4]) + 1, sizeof(char));
    MALLOC_CHECK(stderr, IP);
    strncpy(IP, argv[4], strlen(argv[4]));
    
    
    myAvatar *avatar;
    int slobAvatar = 0;     // the one who doesn't move in maze solver

    int mazePort = atoi(argv[5]);
    
    int width = atoi(argv[7]);
    int height = atoi(argv[8]);
    int shmID = atoi(argv[9]);
    char *maze = (char*) shmat(shmID, 0, 0);
    if (maze == (void *)-1 && errno == EACCES) {

        fprintf(stderr, "shmat failed EACCES\n");
        exit(1);
    }
    if (maze == (void *)-1 && errno == EINVAL) {

        fprintf(stderr, "shmat failed EINVAL\n");
        exit(1);
    }
    if (maze == (void *)-1 && errno == ENOMEM) {

        fprintf(stderr, "shmat failed ENOMEM\n");
        exit(1);
    }

    // Server connection stuff
    int sockfd;
    struct sockaddr_in servaddr;
    
    // Create and check status of server
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        free(IP);
        fprintf(stderr, "Could not create socket.\n");
        return 0;   // false
    }
    
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(IP);
    servaddr.sin_port = htons(mazePort);
    
    // Connect to server
    if (connect(sockfd, (struct sockaddr*) &servaddr, \
                sizeof(servaddr)) < 0) {
        fprintf(stderr, "Unable to connect to server. Exiting.\n");
        free(IP);
        return 0;   // false
    }
    
    // Fire off initial AM_AVATAR_READY
    AM_Message *sendmsg = (AM_Message*)calloc(1, sizeof(AM_Message));
    MALLOC_CHECK(stderr, sendmsg);
    
    sendmsg->type = htonl(AM_AVATAR_READY);
    sendmsg->avatar_ready.AvatarId = htonl(avatarID);  // pack information
    
    // Send ready message to server containing avatar ID
    send(sockfd, sendmsg, sizeof(AM_Message), 0);
    
    // Make a message to get back from server
    AM_Message *receivemsg = (AM_Message*)calloc(1, sizeof(AM_Message));
    MALLOC_CHECK(stderr, receivemsg);

    int firstMove = 1;
    int turn = -1;
    // Start while loop that checks all server messages and updates
    // the avatar's position until either error message or AM_SOLVED received
    for ( ;; ) {
        
        // Zero out the message pointers so they can be re-used
        memset(receivemsg, 0, sizeof(AM_Message));
        memset(sendmsg, 0, sizeof(AM_Message));
        
        // Receive the message and make sure it's not empty
        if (recv(sockfd, receivemsg, sizeof(AM_Message), 0) == 0) {
            fprintf(stderr, "Server terminated early.\n");
            OUTPUT(logFile, "Empty message type. Exiting...\n");
            break;
        }
        
        // Check for server error
        if (IS_AM_ERROR(receivemsg->type)) {
            fprintf(stderr, "Error mask detected error.\n");
        }
        
        // Following if statements will check for all possible server errors
        // In all cases, print to stderr, log the error to output file
        // and break to free resources and return
        
        if (ntohl(receivemsg->type) == AM_UNKNOWN_MSG_TYPE) {
            fprintf(stderr, "AM_UNKNOWN_MSG_TYPE\n");
            OUTPUT(logFile, "Unknown message type. Exiting...\n");
            break;
        }
        
        if (ntohl(receivemsg->type) == AM_NO_SUCH_AVATAR) {
            fprintf(stderr, "AM_NO_SUCH_AVATAR\n");
            OUTPUT(logFile, "No such avatar error. Exiting...\n");
            break;
        }
        
        if (ntohl(receivemsg->type) == AM_UNEXPECTED_MSG_TYPE) {
            fprintf(stderr, "AM_UNEXPECTED_MSG_TYPE\n");
            OUTPUT(logFile, "Unexpected message type. Exiting...\n");
            break;
        }
        
        if (ntohl(receivemsg->type) == AM_AVATAR_OUT_OF_TURN) {
            fprintf(stderr, "AM_AVATAR_OUT_OF_TURN\n");
            OUTPUT(logFile, "Avatar out of turns message type. Exiting...\n");
            break;
        }
        
        if (ntohl(receivemsg->type) == AM_TOO_MANY_MOVES) {
            fprintf(stderr, "AM_AVATAR_TOO_MANY_MOVES\n");
            OUTPUT(logFile, "Avatar too many moves message type. Exiting...\n");
            break;
        }
        
        if (ntohl(receivemsg->type) == AM_SERVER_TIMEOUT) {
            fprintf(stderr, "AM_SERVER_TIMEOUT\n");
            OUTPUT(logFile, "Server timeout message type. Exiting...\n");
            break;
        }
        
        if (ntohl(receivemsg->type) == AM_SERVER_DISK_QUOTA) {
            fprintf(stderr, "AM_SERVER_DISK_QUOTA\n");
            OUTPUT(logFile, "Server disk quota message type. Exiting...\n");
            break;
        }
        
        if (ntohl(receivemsg->type) == AM_SERVER_OUT_OF_MEM) {
            fprintf(stderr, "AM_SERVER_OUT_OF_MEM\n");
            OUTPUT(logFile, "Server out of mem message type. Exiting...\n");
            break;
        }
        
        // Huzzah! Output success to log file.
        if (ntohl(receivemsg->type) == AM_MAZE_SOLVED) {
            
            // Only output this stuff once.
            if (avatarID == slobAvatar) {
                fprintf(stdout, "SOLVED!!!\n");
                fprintf(logFile, "Maze solved with %d avatars on %d"
                        " difficulty in %d moves. The Hash key is: %d.\n", ntohl(receivemsg->maze_solved.nAvatars),\
                        ntohl(receivemsg->maze_solved.Difficulty), ntohl(receivemsg->maze_solved.\
                        nMoves), ntohl(receivemsg->maze_solved.Hash));
            }
            
            break;
        }
        
        if (ntohl(receivemsg->type) == AM_AVATAR_TURN) {
            // Only look at messages from the relevant reply messages
            if (ntohl(receivemsg->avatar_turn.TurnId) == avatarID) {
                
                if (firstMove) {
                    // Initialize the avatar.
                    avatar = (myAvatar*)calloc(1, sizeof(myAvatar));
                    MALLOC_CHECK(stderr, avatar);
                    avatar->fd = avatarID;
                    avatar->lastMoveDir = M_NORTH;  // everyone goes north initially
                    
                    // Initially, avatar's previous position and current position
                    // are the same. Retrieve these from server.
                    avatar->pos.x = ntohl(receivemsg->avatar_turn.Pos[avatarID].x);
                    avatar->pos.y = ntohl(receivemsg->avatar_turn.Pos[avatarID].y);
                    
                    // No previous initially.
                    
                    // Send the avatar north.
                    sendmsg->type = htonl(AM_AVATAR_MOVE);
                    sendmsg->avatar_move.AvatarId = htonl(avatarID);
                    sendmsg->avatar_move.Direction = htonl(M_NORTH);
                    
                    if (VERBOSE) {
                        fprintf(stdout, "Avatar %d: Initial pos (%d, %d) moved NORTH\n", avatarID,\
                                avatar->pos.x, avatar->pos.y);
                    }
                    // Send ready message to server containing avatar ID
                    send(sockfd, sendmsg, sizeof(AM_Message), 0);
                    turn = 1;
                    firstMove = 0;

                    if (GRAPHICS) {
                        //initialize graphics
                        AddAvatar(maze,avatar,width);
                        PrintMaze(maze, width, height);
                    }
                    
                    continue;
                    
                }
                
                else {  // not first move
                    
                    // If it's the avatar standing still, arbitrarily picked as
                    // avatar with ID = 0, then always stand still.
                    if (avatarID == slobAvatar) {
                        sendmsg->type = htonl(AM_AVATAR_MOVE);
                        sendmsg->avatar_move.AvatarId = htonl(avatarID); // should be 0
                        sendmsg->avatar_move.Direction = htonl(M_NULL_MOVE);
                        send(sockfd, sendmsg, sizeof(AM_Message), 0);
                        turn++;
                        continue;
                    }
                    
                    // Make the previous the current position
                    avatar->prev.x = avatar->pos.x;
                    avatar->prev.y = avatar->pos.y;
                    turn++;
                    // Make current position the new one from the server
                    int newX = ntohl(receivemsg->avatar_turn.Pos[avatarID].x);
                    int newY = ntohl(receivemsg->avatar_turn.Pos[avatarID].y);
                    avatar->pos.x = newX;
                    avatar->pos.y = newY;
                    
                    // See if the slob and the current avatar are on the same spot.
                    int deltaX = avatar->pos.x - ntohl(receivemsg->avatar_turn.Pos[slobAvatar].x);
                    int deltaY = avatar->pos.y - ntohl(receivemsg->avatar_turn.Pos[slobAvatar].y);
                    int checkSameCell = 0;
                    
                    if ((deltaY == 0) && (deltaX == 0)) {
                        checkSameCell = 1;
                    }
                    // If avatar is on same spot as slob, slob has been found.
                    // Don't move the other avatar.
                    if (checkSameCell) {
                        sendmsg->type = htonl(AM_AVATAR_MOVE);
                        sendmsg->avatar_move.AvatarId = htonl(avatarID);
                        sendmsg->avatar_move.Direction = htonl(M_NULL_MOVE);
                        send(sockfd, sendmsg, sizeof(AM_Message), 0);
                        turn++;
                        continue;
                    }
                    
                    // Avatar is not slob and has not yet met slob.
                    else {
                        
                        // See if the last move was productive
                        int lastMove = checkLastMove(avatar);
                        avatar->lastMoveSuccess = lastMove;

                        //update graphics based on last move

                        if(!lastMove){
                            AddWall(maze,avatar,width);
                        }
                        else{
                            //DelAvatar(maze,avatar,width);//comment out to see history
                            if(!AddMark(maze,avatar,width))//blocks square if test passes
                                AddAvatar(maze,avatar,width);
                        }
                        
                        if (GRAPHICS) {
                            PrintMaze(maze,width,height);
                        }
                        
                        
                        

                        //prep next move
                        int nextMove = getMove(avatar);
                        avatar->lastMoveDir = nextMove;
                        while(isKnown(maze, avatar, width)){
                            avatar->lastMoveSuccess = false;
                            nextMove = getMove(avatar);
                            avatar->lastMoveDir = nextMove;
                        }
                        
                        turn++;
                        sendmsg->type = htonl(AM_AVATAR_MOVE);
                        sendmsg->avatar_move.AvatarId = htonl(avatarID);
                        sendmsg->avatar_move.Direction = htonl(nextMove);
                        
                        if (VERBOSE) {
                            fprintf(stdout, "======== Turn %d ========\n", turn);
                            if (nextMove == M_NORTH) {
                                fprintf(stdout, "Avatar %d: Moved NORTH from (%d, %d).\n", avatarID,\
                                        avatar->pos.x, avatar->pos.y);
                            }
                            if (nextMove == M_SOUTH) {
                                fprintf(stdout, "Avatar %d: Moved SOUTH from (%d, %d).\n", avatarID,\
                                        avatar->pos.x, avatar->pos.y);
                            }
                            
                            if (nextMove == M_WEST) {
                                fprintf(stdout, "Avatar %d: Moved WEST from (%d, %d).\n", avatarID,\
                                        avatar->pos.x, avatar->pos.y);
                            }
                            
                            if (nextMove == M_EAST) {
                                fprintf(stdout, "Avatar %d: Moved EAST from (%d, %d).\n", avatarID,\
                                        avatar->pos.x, avatar->pos.y);
                            }
                            fprintf(stdout, "\n");
                        }
                        
                        send(sockfd, sendmsg, sizeof(AM_Message), 0);
                    }
                    
                }
            }
            
        }
        
    }
    shmctl(shmID, IPC_RMID, NULL);
    free(sendmsg); free(receivemsg); free(IP); free(avatar);
    fclose(logFile);
    close(sockfd);
    return 1;
    
}
示例#4
0
void* AvatarFun(void* arg)
{
 	int sockfd;
    struct sockaddr_in servaddr;
    AvatarData* data = (AvatarData*) arg;

	struct timespec tim, tim2;
  	tim.tv_sec = 0;
   	tim.tv_nsec = 50000;

 	// Create a socket for the client
    // If sockfd<0 there was an error in the creation of the socket
    if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
    	perror("Problem in creating the socket");	
        exit(2);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr(data->IPadd);
    servaddr.sin_port =  htons(data->MazePort); //convert to big-endian order
    
    // Connection of the client to the socket 
    if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
        perror("Problem in connecting to the server");
        exit(4);
    }
 	
 	// Send AM_AVATAR_READY msg for each avatar
    struct AM_Message readymsg, recvmsg;
	readymsg.type = htonl(AM_AVATAR_READY);
    readymsg.avatar_ready.AvatarID = htonl(data->AvatarID);
    send(sockfd, &readymsg, sizeof(readymsg), 0);

  	int old_dir = -1, new_dir = -1;
    int blocked = 0;
    XYPos* old_pos = (XYPos*) calloc(1, sizeof(XYPos));
    XYPos* new_pos = (XYPos*) calloc(1, sizeof(XYPos));
    int exitvalue = 6;

	// receive the first message from the server
    recv(sockfd, &recvmsg, sizeof(recvmsg), 0);
    old_pos->x = -1;
    old_pos->y = -1;
    
    new_pos->x = ntohl(recvmsg.avatar_turn.Pos[data->AvatarID].x);
    new_pos->y = ntohl(recvmsg.avatar_turn.Pos[data->AvatarID].y);
    int turnId = ntohl(recvmsg.avatar_turn.TurnId);

    // set goal vertex
	if (data->AvatarID == 0) {
		goalx = new_pos->x;
		goaly = new_pos->y;
	}
	
	while (1) {
		// if it's this avatar's turn
		if (data->AvatarID == turnId) {
			if(pthread_mutex_trylock(&avatar_mutex) != 0) nanosleep(&tim , &tim2);
			if (new_pos->x == goalx && new_pos->y == goaly) {
				new_dir = M_NULL_MOVE;
			} else {
				// figure out how to move
				new_dir = whereToTurn(old_dir, blocked, new_pos, data->MazeMap->map);
			}
			// ask to move 
			int ask = askToMoveAvatar(sockfd, new_dir, data->AvatarID);
			if (ask == 0) {
				cleanup(old_pos, new_pos, data, sockfd, exitvalue);
				exit(9);
			}
			numMoves++;
		}
		
		// Receive response from Server
		if (recv(sockfd, &recvmsg, sizeof(recvmsg), 0) < 0) {
			fprintf(stderr, "error receiving message from server.\n");
			exit (14);
		}

		if (ntohl(recvmsg.type) == AM_MAZE_SOLVED) {		// solved the maze
			for (int i = 0; i < data->nAvatars; i++) {
				new_pos->x = goalx;
				new_pos->y = goaly;
				updateLocations(data->locations, new_pos, turnId);
			}
			if (data->AvatarID == 0) {
				printMapToConsole(data->MazeMap->width, data->MazeMap->height, 
						data->locations, data->nAvatars, numMoves);
				printf("Maze Solved!\n");

				char *solved = (char*) calloc(100, sizeof(char));
				sprintf(solved, "Maze solved for %d avatars and %d "
						"difficulty in %d moves.\n",
						ntohl(recvmsg.maze_solved.nAvatars),
						ntohl(recvmsg.maze_solved.Difficulty),
						ntohl(recvmsg.maze_solved.nMoves));
				int writesolved = writeToLog(data->filename, solved);
				free(solved);
				if (writesolved == 0) {
					cleanup(old_pos, new_pos, data, sockfd, exitvalue);
					exit(10);
				}
		
				char *success = (char*) calloc(50, sizeof(char));
				sprintf(success, "Success code: %u\n",
						ntohl(recvmsg.maze_solved.Hash));
				int writesuccess = writeToLog(data->filename, success);
				free(success);
				if (writesuccess == 0) {
					cleanup(old_pos, new_pos, data, sockfd, exitvalue);
					exit(11);
				}
			}
			cleanup(old_pos, new_pos, data, sockfd, exitvalue);
			return NULL;

		} else if (ntohl(recvmsg.type) == AM_TOO_MANY_MOVES) {	// too many moves
			if (data->AvatarID == 0) {
				printf("Ran out of moves :(\n");
				int writemoves = writeToLog(data->filename, "Ran out of moves\n");
				if (writemoves == 0) {
					cleanup(old_pos, new_pos, data, sockfd, exitvalue);
					exit(12);
				}
			}
			cleanup(old_pos, new_pos, data, sockfd, exitvalue);
			return NULL;

		} else if (ntohl(recvmsg.type) == AM_AVATAR_TURN) {		// regular turn
			old_pos->x = new_pos->x;
			old_pos->y = new_pos->y;
			new_pos->x = ntohl(recvmsg.avatar_turn.Pos[data->AvatarID].x);
			new_pos->y = ntohl(recvmsg.avatar_turn.Pos[data->AvatarID].y);

			updateLocations(data->locations, new_pos, data->AvatarID);

		} else if (!IS_AM_ERROR(ntohl(recvmsg.type))) {  // error message
			if (data->AvatarID == 0) {
				fprintf(stderr, "Error: message type.\n");
				int writeerror = writeToLog(data->filename, "Error reading message type.\n");
				if (writeerror == 0) {
					cleanup(old_pos, new_pos, data, sockfd, exitvalue);
					exit(13);
				}
			}
			cleanup(old_pos, new_pos, data, sockfd, exitvalue);
			exit(6);
		} else {
			printf("this is the recvmsg type: %u\n", ntohl(recvmsg.type));
			fprintf(stderr, "Undefined error receiving turn message from server.\n");
			cleanup(old_pos, new_pos, data, sockfd, exitvalue);
			exit(6);
		}
		
		if (data->AvatarID == turnId) {
			int check = updateLog(data->filename, data->AvatarID, new_dir, 
					data->nAvatars, data->locations);
			if (check == 0) {
				cleanup(old_pos, new_pos, data, sockfd, exitvalue);
				exit(8);
			}

			// update blocked
			if (new_pos->x == old_pos->x && new_pos->y == old_pos->y) {
				blocked = 1;
			} else {
				blocked = 0;
			}
			
			data->MazeMap = updateMazeMap(data->MazeMap, old_pos, new_pos, new_dir);
			if (!(data->MazeMap)) {
				fprintf(stderr, "Error updating the MazeMap.\n");
				exit(7);
			}
			printMapToConsole(data->MazeMap->width, data->MazeMap->height, 
					data->locations, data->nAvatars, numMoves);
		}
		turnId = ntohl(recvmsg.avatar_turn.TurnId);
		old_dir = new_dir;
		pthread_mutex_unlock(&avatar_mutex);
	}
}
/*
 * avatarMake
 *
 * Function: Initialize each avatar and send move messages during their respective turns
 *
 * Input: @id - current avatar's ID
 *
 */
void *avatarMake (void *id){
  int avatarID = (intptr_t)id;

  // Creating ready message
  AM_Message am_ready;
  memset(&am_ready, 0, sizeof(AM_Message));
  am_ready.type = htonl(AM_AVATAR_READY);
  am_ready.avatar_ready.AvatarId = htonl(avatarID);

  // Creting socket for the avatar
  int sockId;
  if ((sockId = socket(AF_INET, SOCK_STREAM, 0)) < 0){
    fprintf(stderr, "ERROR IN SOCKET 2");
    fprintf(logFile, "ERROR IN SOCKET");
    exit(1);
  }

  // Connect the client to socket                                                             
  if (connect(sockId, (struct sockaddr *) &maze_address, sizeof(maze_address)) < 0) {
    fprintf(stderr, "There was a problem connecting client to the socket 2\n");
    fprintf(logFile, "There was a problem connecting client to the socket\n");    
    exit(1);
  }

  // Sending message to our server
  send(sockId,&am_ready,sizeof(am_ready),0);
  
  // Receiving and checking reply from server
  AM_Message receiveMessage;
  if (recv(sockId,&receiveMessage,sizeof(receiveMessage),0) == 0){
    fprintf(stderr,"The server connection was closed 2\n");
    fprintf(logFile,"The server connection was closed\n");    
    exit(1);
  }
  
  if (ntohl(receiveMessage.type) != AM_AVATAR_TURN){
    fprintf(stderr,"Initialization failed 2");
    fprintf(logFile,"Initialization failed");
    exit(1);
  }
 
  // initialize avatar position
  pthread_mutex_lock(&init_mutex);
  avatarGroup[avatarID]->currpos->x = ntohl(receiveMessage.avatar_turn.Pos[avatarID].x);
  avatarGroup[avatarID]->currpos->y = ntohl(receiveMessage.avatar_turn.Pos[avatarID].y);
  avatarGroup[avatarID]->prevpos->x = avatarGroup[avatarID]->currpos->x;
  avatarGroup[avatarID]->prevpos->y = avatarGroup[avatarID]->currpos->y;
  pthread_mutex_unlock(&init_mutex);

  avFlag++;

  while(avFlag != avatarNum){
    sleep(1);
  }

  int move;
  while(1){
    // enters only on the avatar's specified turn
    if(ntohl(receiveMessage.avatar_turn.TurnId) == avatarID){

      pthread_mutex_lock(&turn_mutex);
      totalMoves++;
      fprintf(logFile,"\nMOVE #%d\n",totalMoves);
      fprintf(logFile,"avatar %d is at position (%d,%d)\n",avatarID,avatarGroup[avatarID]->currpos->x,avatarGroup[avatarID]->currpos->y);
      
      turnID = avatarID;

      setTarget();
      
      // figure out what move to make (FIX NESW)
      move = nextMove(avatarID, avatarGroup[avatarID]->currpos,avatarGroup[avatarID]->prevpos);
      
      if (move == -1){
        fprintf(stderr, "Maze node null\n");
        fprintf(logFile,"Maze node null\n");
        exit(1);
      }
      
      
      // print to file saying what move the avatar is trying to make
      fprintf(logFile,"Avatar %d is trying to move %s \n",avatarID,translateDirection(move));
      // Create move message
      AM_Message moveMessage;
      memset(&moveMessage,0,sizeof(AM_Message));
      moveMessage.type = htonl(AM_AVATAR_MOVE);
      moveMessage.avatar_move.Direction = htonl(move);
      moveMessage.avatar_move.AvatarId = htonl(avatarID);
      
      // Sending move message
      send(sockId,&moveMessage,sizeof(moveMessage),0);

      //receive and check message
      while (ntohl(receiveMessage.avatar_turn.TurnId) == avatarID){
        if (recv(sockId,&receiveMessage,sizeof(receiveMessage),0) == 0){
        fprintf(stderr,"The server connection was closed 3\n");
        fprintf(logFile,"The server connection was closed\n");
        exit(1);
        }

        if( totalMoves == (AM_MAX_MOVES*(difficulty+1)*avatarNum)){
          if(terminate == 0){
            fprintf(stderr,"Exceeded the max number of moves\n");
            fprintf(logFile,"\nEXCEEDED THE MAX NUMBER OF MOVES");
            terminate = 1;
          }
          exit (1);
        }
  
        if(ntohl(receiveMessage.type) == AM_MAZE_SOLVED){
          DrawMaze(height, width, avatarGroup, maze, avatarID, avatarNum, filename);
          if (terminate == 0 ){
            printf("solved");
            fprintf(logFile,"\nMAZE SOLVED!");
            terminate = 1;
          }
          return 0;
        }
        
        if(IS_AM_ERROR(ntohl(receiveMessage.type))){
          fprintf(stderr,"Error from the server 3");
          fprintf(logFile,"Error from the server");
          exit(1);
        }
      }

      if (move != M_NULL_MOVE){
        XYPos *tmp = (XYPos *)malloc(sizeof(XYPos));
        tmp->x = ntohl(receiveMessage.avatar_turn.Pos[avatarID].x);
        tmp->y = ntohl(receiveMessage.avatar_turn.Pos[avatarID].y);
        if (avatarMoved(avatarID, avatarGroup[avatarID]->currpos, tmp, move) == 1){
          // if the avatar moved, update its previous and current positions
          avatarGroup[avatarID]->prevpos->x = avatarGroup[avatarID]->currpos->x;
          avatarGroup[avatarID]->prevpos->y = avatarGroup[avatarID]->currpos->y;
          avatarGroup[avatarID]->currpos->x = tmp->x;
          avatarGroup[avatarID]->currpos->y = tmp->y;
        }
        free(tmp);
      }
     
      // update the maze graphic
      DrawMaze(height, width, avatarGroup, maze, avatarID, avatarNum, filename);
      pthread_mutex_unlock(&turn_mutex);
    }
    // when it's not an avatar's turn, it continues to check server messages
    else{
        //receive and check message
      if (recv(sockId,&receiveMessage,sizeof(receiveMessage),0) == 0){
        if(terminate == 0 ){
          fprintf(stderr,"The server connection was closed 3\n");
          fprintf(logFile,"The server connection was closed\n");
          terminate = 1;
        }
        exit(1);
      }

      if( totalMoves == (AM_MAX_MOVES*(difficulty+1)*avatarNum) ){
              if(terminate == 0){
          fprintf(stderr,"Exceeded the max number of moves\n");
          fprintf(logFile,"\nEXCEEDED MAX NUMBER OF MOVES");
          terminate = 1;
        }
        exit (1);
      }

      if(ntohl(receiveMessage.type) == AM_MAZE_SOLVED){
        DrawMaze(height, width, avatarGroup, maze, avatarID, avatarNum, filename);
        if(terminate == 0){
          printf("solved");
          fprintf(logFile,"\nMAZE SOLVED!");
          terminate = 1;
        }
        return 0;
      }
      
      if(IS_AM_ERROR(ntohl(receiveMessage.type))){
        if(terminate == 0){
          fprintf(stderr,"Error from the server 3");
          fprintf(logFile,"Error from the server");
          terminate = 1;
        }
        exit(1);
      }

    }
  }
  
  return 0;
}
示例#6
0
int main(int argc, char **argv){
	//General parameter checks

	if (argc != 4){
		fprintf(stdout, "Error: Incorrect number of paramters.");
		exit(1);
	}
	int numAvatars= atoi(argv[1]);

	if ((numAvatars < 1) || (numAvatars > 10)){
		fprintf(stdout, "Error: Number of avatars must be from 1 to 10.");
		exit(1);
	}
	int difficulty= atoi(argv[2]);
	if ((difficulty < 0) || (difficulty > 9)){
		fprintf(stdout, "Error: Difficulty must be from 0 to 9.");
		exit(1);
	}

	char *hostName= argv[3];
	if (strcmp(hostName, "flume.cs.dartmouth.edu") != 0){
		fprintf(stdout, "Error: hostname must be flume.cs.dartmouth.edu");
		exit(1);
	}

	//Get the ip address of the hostname
	char ip[200]; //ip definitely won't be longer than 200 characters
	getIP(hostName, ip);
	fprintf(stdout, "Host %s resolved to %s\n", hostName, ip);


	//Start the log file now
	char *userName = getlogin();
	char *fileLog = (char*)malloc(sizeof(char)*(strlen("Amazing_")+strlen(userName)+ \
	strlen(argv[1])+strlen(argv[2])+strlen("__.log")+1));
	if (fileLog == NULL){
		fprintf(stdout, "Error: Memory allocation error.");
		exit(1);
	}
	sprintf(fileLog, "Amazing_%s_%s_%s.log", userName, argv[1], argv[2]); 
	
	/* Adapted from echoClient.c example */
	int sockfd;
	struct sockaddr_in servaddr;
	AM_Message *send_signal = (struct AM_Message*)malloc(sizeof(AM_Message));
	AM_Message *receive_signal = (struct AM_Message*)malloc(sizeof(AM_Message));

	//Create a socket for the client
	//If sockfd<0 there was an error in the creation of the socket
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) <0) {
		perror("Problem in creating the socket");
		exit(2);
	}

	//Creation of the socket
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr= inet_addr(ip); // flume.cs.dartmouth.edu IP
	servaddr.sin_port =  htons(atoi(AM_SERVER_PORT)); //convert to big-endian order

	//Connection of the client to the socket 
	if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0) {
		perror("Problem in connecting to the server");
		exit(3);
	}
	printf("Connection Succesful.\n"); // If we got here, connection didnt fail


	// Create AM_INIT signal
	send_signal->type = htonl(AM_INIT);
	send_signal->init.nAvatars = htonl(numAvatars);
	send_signal->init.Difficulty = htonl(difficulty);

	
	// Send initial signal to server
	send(sockfd, send_signal, sizeof(*send_signal), 0); 

	// Receive from server
	if (recv(sockfd, receive_signal, sizeof(*receive_signal),0) == 0){
		//error: server terminated prematurely
		perror("The server terminated prematurely"); 
		exit(4);
	}


	if (IS_AM_ERROR(ntohl(receive_signal->type))){
			printf("Error on return signal.\n");
			exit(1);
	}


	printf("REC TYPE:%d\n",ntohl(receive_signal->type));
	if(receive_signal->type == AM_INIT_FAILED){
		printf("Received AM_INIT_OK\n\n");
	}

	int mazePort = ntohl(receive_signal->init_ok.MazePort);
	int mazeWidth = ntohl(receive_signal->init_ok.MazeWidth);
	int mazeHeight = ntohl(receive_signal->init_ok.MazeHeight);

	printf("INIT_OK SIGNAL RECEIVED:\n");
	printf("MazePort: %d\n", mazePort);
	printf("MazeWidth: %d\n", mazeWidth);
	printf("MazeHeight: %d\n", mazeHeight);

	//Start the avatar program with appropriate arguments
	//Need to add memory allocation failure errors for the following
	//and free as appropriate
	int numWidthInts= snprintf(NULL, 0, "%d", mazeWidth);
	char *widthString = (char*)malloc(numWidthInts+1);
	sprintf(widthString, "%d", mazeWidth);

	int numHeightInts= snprintf(NULL, 0, "%d", mazeHeight);
	char *heightString = (char*)malloc(numHeightInts+1);
	sprintf(heightString, "%d", mazeHeight);
	
	int numInts= snprintf(NULL, 0, "%d", mazePort);
	char *mazePortString= (char*)malloc(numInts+1);
	sprintf(mazePortString, "%d", mazePort);


	execl("./avatar", "./avatar", argv[1], argv[2], ip, mazePortString, fileLog, widthString, heightString, NULL);
	perror("execl() failure!\n\n");

	//May have to move the location of this stuff
	shutdown(sockfd, 2);
	free(send_signal);
	free(receive_signal);

	free(widthString);
	free(heightString);
	free(mazePortString);
	free(fileLog);

	exit(0);
}
示例#7
0
/*====================================================================*/
int agent(int curAvatar, int nAvatars, int xlen, int ylen, char *hostname, key_t k,
                uint32_t port, int algo)
{
        int shmid;
        int s;
        char *outstring;
        WorldMap *globalmap;
        AM_Message outMessage;
        AM_Message inMessage;
        XYPos pos[AM_MAX_AVATAR];
        Direction movdir;
        int iterations = 0;
        int i;
        bool firstMove = true;
        int fd_log;
        LogMessage lmsg;
        float pknown;

        /* makes named pipe to logger */
        if (mkfifo(FIFO_NAME, 0666) == -1) {
                if (errno != EEXIST) {
                        perror("mkfifo");
                        return -1;
                }
        }

        fd_log = open(FIFO_NAME, O_WRONLY);
        if (fd_log == -1) {
                fprintf(stderr, "Failed to connect to log process\n");
                perror("open");
                return -1;
        }

        LOG(lmsg, fd_log, LVL_VERB, "%d connected to server", curAvatar);

        /* start with nonsense values to pos so we never assume we have a wall in front
         * of us on the first turn
         */
        for (i = 0; i < nAvatars; i++) {
                pos[i].x = AM_MAX_GRID_SIZE + 1;
                pos[i].y = AM_MAX_GRID_SIZE + 1;
        }

        /* start facing North */
        movdir = N;

        /* get shared memory */
        if ((shmid = shmget(k, sizeof(WorldMap), 0644 | IPC_CREAT)) == -1) {
                perror("shmget");
                LOG(lmsg, fd_log, LVL_FATAL, "Could not get id for shared memory: %s",\
                        strerror(errno));
        }

        /* attach to the segment and get a pointer to it */
        globalmap = shmat(shmid, (void *)0, 0);
        if (globalmap == (WorldMap *)(-1)) {
                perror("shmat");
                shmctl(shmid, IPC_RMID, NULL);
                fprintf(stderr, "Could not attach to shared memory\n");
                return (-1);
        }

        /* Avatar 0 initialize global map */
        if (curAvatar == 0) {
                LOG(lmsg, fd_log, LVL_VERB, "initializing global worldmap%s", "");
                globalmap->xlen = xlen;
                globalmap->ylen = ylen;
                initWorldMap(globalmap);
        } else {
                sleep(1); /* allow time for the log file to be initialized */
        }

        /* connect to the server and send avatar ready message */
        s = connectToServer(hostname, port);
        if (s < 0) {
                LOG(lmsg, fd_log, LVL_INFO, "Avatar %d Could not connect to server",
                                curAvatar+1);
                shmctl(shmid, IPC_RMID, NULL);
                return -1;
        }

        memset(&outMessage, 0, sizeof(outMessage));
        outMessage.type = AM_AVATAR_READY;
        outMessage.avatar_ready.AvatarId = curAvatar;
        sendAMMessage(s, outMessage);

        /* main agent loop */
        do {
                /* Get the next message from the server */
                inMessage = receiveAMMessage(s);
                if (IS_AM_ERROR(inMessage.type)) {
                        if (inMessage.type & AM_AVATAR_OUT_OF_TURN)
                                continue;
                        printAMError(fd_log, inMessage.type);
                        shmctl(shmid, IPC_RMID, NULL);
                        return -1;
                }
                /* if the message is not the right type */
                if (!(inMessage.type & AM_AVATAR_TURN))
                        continue;

                /* if it is our turn */
                if (inMessage.avatar_turn.TurnId == curAvatar) {
                        pthread_mutex_lock(&globalmap->mapMutex);
                        /* Get our next move */
                        movdir = getNextMove(*globalmap, inMessage.avatar_turn.Pos,
                                        movdir, pos[curAvatar], nAvatars, curAvatar,
                                        algo);

                        /* initialize outMessage */
                        memset(&outMessage, 0, sizeof(outMessage));
                        outMessage.type = AM_AVATAR_MOVE;
                        outMessage.avatar_move.AvatarId = curAvatar;
                        outMessage.avatar_move.Direction = dirToMoveDir(movdir);
                        sendAMMessage(s, outMessage);

                        iterations++;
                        /* Avatar 0 counts iterations */
                        if (curAvatar == 0) {
				fprintf(stdout, "\033[2J\033[1;1H");
                                printf("iteration %d\n", iterations);
                                outstring = serializeWorldMap(*globalmap, nAvatars,
                                                inMessage.avatar_turn.Pos);
                                /* Print to stdout */
                                fprintf(stdout, "%s\n", outstring);
                                free(outstring);
                                if (algo == 2) {
                                        if (!(connectedToAll(*globalmap,
                                                                        pos[0], nAvatars))) {
                                                pknown = percentKnown(*globalmap, nAvatars);
                                        }
                                        fprintf(stdout, "percent known %.1f %%\n",
                                                        pknown*100);
                                }

                                for (i = 0; i < nAvatars; i++) {
                                        LOG(lmsg, fd_log, LVL_INFO,
                                                        "avatar %d (% 3d,% 3d) -> "
                                                        "(% 3d,% 3d)", i+1, (int)pos[i].x,
                                                        (int)pos[i].y,
                                                        (int)inMessage.avatar_turn.Pos[i].x,
                                                        (int)inMessage.avatar_turn.Pos[i].y);
                                }
                        }
                        /* Update our position */
                        for (i = 0; i < nAvatars; i++)
                                pos[i] = inMessage.avatar_turn.Pos[i];
                } else if (inMessage.avatar_turn.TurnId ==
                                (curAvatar + 1)%nAvatars && !firstMove) {
                        /* Update with results of previous move */
                        if (inMessage.type & AM_AVATAR_TURN)
                                updateWorldMap(globalmap, pos[curAvatar], movdir, inMessage,
                                                curAvatar, nAvatars, algo);
                        pthread_mutex_unlock(&globalmap->mapMutex);
                }
                firstMove = false;
        } while (!(inMessage.type & AM_MAZE_SOLVED) &&
                        !(inMessage.type == AM_TOO_MANY_MOVES));


        /* Detach and (if no other process is connected) deallocate shared memory */
        shmctl(shmid, IPC_RMID, NULL);
        close(s);

        if (curAvatar == 0) {
                if (inMessage.type & AM_MAZE_SOLVED) {
                        printf("Moves to solve: %" PRIu32, inMessage.maze_solved.nMoves);
                        printf("\n");
                        printf("Size = %dx%d\n", xlen, ylen);
                        printf("Algorithm = %d\n", algo);
                        printf("# of Avatars = %d\n", nAvatars);

                        /* print to log */
                        LOG(lmsg, fd_log, LVL_INFO, "Moves to Solve: %" PRIu32,
                                        inMessage.maze_solved.nMoves);
                        LOG(lmsg, fd_log, LVL_INFO, "Hash: %" PRIu32,
                                        inMessage.maze_solved.Hash);

                } else {
                        LOG(lmsg, fd_log, LVL_INFO, "Maze not solved after ~%d moves",
                                        iterations * nAvatars);
                        memset(&lmsg, 0, sizeof(lmsg));
                }
        }
        sleep(1);
        close(fd_log);
        unlink(FIFO_NAME);
        pthread_mutex_destroy(&globalmap->mapMutex);
        return 0;
}