Thread: Program for Battleboats (Variant of Battleship)

  1. #1
    Registered User
    Join Date
    May 2015
    Posts
    1

    Program for Battleboats (Variant of Battleship)

    Hi all. This is my first ever post, so let me know if I do anything wrong so I can learn. I am writing code to create Battleboats, which is essentially Battleship, on a MicroChip PIC32. When I run my code, sometimes I can play one or two turns before I get a message parsing protocol error. My code is hundreds of lines long, and I am having trouble figuring out what is wrong. Sometimes the game will not even start at all. I think my issue lies in my ProtocolDecode() and ProtocolGetTurnOrder() functions, so I am going to post these two, with comments describing exactly how they are supposed to work. If you need any other code, or header files that contain the structures and enumerations I am using, just let me know. Thank you!
    Code:
    /**
     * This function decodes a message into either the NegotiationData or GuessData structs depending
     * on what the type of message is. This function receives the message one byte at a time, where the
     * messages are in the format defined by MESSAGE_TEMPLATE, with payloads of the format defined by
     * the PAYLOAD_TEMPLATE_* macros. It returns the type of message that was decoded and also places
     * the decoded data into either the `nData` or `gData` structs depending on what the message held.
     * The onus is on the calling function to make sure the appropriate structs are available (blame the
     * lack of function overloading in C for this ugliness).
     *
     * PROTOCOL_PARSING_FAILURE is returned if there was an error of any kind (though this excludes
     * checking for NULL pointers), while
     *
     * @param parser The struct holding the data for this instance of the parser. Allows for multiple
     *               protocol decoding streams.
     * @param in The next character in the NMEA0183 message to be decoded.
     * @param nData A struct used for storing data if a message is decoded that stores NegotiationData.
     * @param gData A struct used for storing data if a message is decoded that stores GuessData.
     * @return A value from the UnpackageDataEnum enum.
     */
    ProtocolParserStatus ProtocolDecode(char in, NegotiationData *nData, GuessData *gData)
    {
        switch (parserState) {
        case WAITING:
            if (in == '$') {
                parserIndex = 0;
                parserState = RECORDING;
                return PROTOCOL_PARSING_GOOD;
            } else {
                return PROTOCOL_WAITING;
            }
            break;
        case RECORDING:
            if (parserIndex > PROTOCOL_MAX_PAYLOAD_LEN) {
                parserState = WAITING;
                return PROTOCOL_PARSING_FAILURE;
            } else if (in == '*') {
                parserState = FIRST_CHECKSUM_HALF;
                parserIndex++;
                return PROTOCOL_PARSING_GOOD;
            } else {
                parserPayload[parserIndex] = in;
                parserIndex++;
                return PROTOCOL_PARSING_GOOD;
            }
            break;
        case FIRST_CHECKSUM_HALF:
            // If valid hex char
            if (((in >= '0') && (in <= '9')) || ((in >= 'a') && (in <= 'f'))
                    || ((in >= 'A') && (in <= 'F'))) {
                parserCheckSum[0] = in;
                parserState = SECOND_CHECKSUM_HALF;
                return PROTOCOL_PARSING_GOOD;
            } else {
                parserState = WAITING;
                return PROTOCOL_PARSING_FAILURE;
            }
            break;
        case SECOND_CHECKSUM_HALF:
            // If valid hex cha
            if (((in >= '0') && (in <= '9')) || ((in >= 'a') && (in <= 'f'))
                    || ((in >= 'A') && (in <= 'F'))) {
                parserCheckSum[1] = in;
                parserState = NEWLINE;
    
    
                // calculates chcksum and compares to decoded checksum
                uint8_t calculatedCheckSum;
                uint8_t decodedCheckSum;
                if(parserPayload[0] == 'C' && parserPayload[1] == 'O'){
                    parserPayload[7] = '\0';
                }
                parserPayload[7] = '\0';
                calculatedCheckSum = CheckSum(parserPayload);
                decodedCheckSum = CheckSumDecode(parserCheckSum);
                if (calculatedCheckSum == decodedCheckSum) {
                    parserPayload[parserIndex] = '\0';
                    parserState = NEWLINE;
                    return PROTOCOL_PARSING_GOOD;
                } else {
                    parserState = WAITING;
                    return PROTOCOL_PARSING_FAILURE;
                }
            } else {
                parserState = WAITING;
                return PROTOCOL_PARSING_FAILURE;
            }
            break;
        case NEWLINE:
            if (in == '\n') {
                char *identifier;
                identifier = strtok(parserPayload, "$,*");
                //identifier = strtok(NULL, ",*");
                if (strcmp(identifier, "COO") == 0) {
                    gData->row = atoi(strtok(NULL, ",*"));
                    gData->col = atoi(strtok(NULL, ",*"));
                    parserState = WAITING;
                    return PROTOCOL_PARSED_COO_MESSAGE;
                } else if (strcmp(identifier, "HIT") == 0) {
                    gData->row = atoi(strtok(NULL, ",*"));
                    gData->col = atoi(strtok(NULL, ",*"));
                    gData->hit = atoi(strtok(NULL, ",*"));
                    parserState = WAITING;
                    return PROTOCOL_PARSED_HIT_MESSAGE;
                } else if (strcmp(identifier, "CHA") == 0) {
                    nData->encryptedGuess = atoi(strtok(NULL, ",*"));
                    nData->hash = atoi(strtok(NULL, ",*"));
                    parserState = WAITING;
                    return PROTOCOL_PARSED_CHA_MESSAGE;
                } else if (strcmp(identifier, "DET") == 0) {
                    nData->guess = atoi(strtok(NULL, ",*"));
                    nData->encryptionKey = atoi(strtok(NULL, ",*"));
                    parserState = WAITING;
                    return PROTOCOL_PARSED_DET_MESSAGE;
                } else {
                    parserState = WAITING;
                    return PROTOCOL_PARSING_FAILURE;
                }
            } else {
                parserState = WAITING;
                return PROTOCOL_PARSING_FAILURE;
            }
            break;
        }
        return PROTOCOL_PARSING_FAILURE;
    }
    
    /**
     * This function returns a TurnOrder enum type representing which agent has won precedence for going
     * first. The value returned relates to the agent whose data is in the 'myData' variable. The turn
     * ordering algorithm relies on the XOR() of the 'encryptionKey' used by both agents. The least-
     * significant bit of XOR(myData.encryptionKey, oppData.encryptionKey) is checked so that if it's a
     * 1 the player with the largest 'guess' goes first otherwise if it's a 0, the agent with the
     * smallest 'guess' goes first. The return value of TURN_ORDER_START indicates that 'myData' won,
     * TURN_ORDER_DEFER indicates that 'oppData' won, otherwise a tie is indicated with TURN_ORDER_TIE.
     * There is no checking for NULL pointers within this function.
     * @param myData The negotiation data representing the current agent.
     * @param myData The negotiation data representing the opposing agent.
     * @return A value from the TurnOrdering enum representing which agent should go first.
     */
    TurnOrder ProtocolGetTurnOrder(const NegotiationData *myData, const NegotiationData *oppData)
    {
        uint8_t highLowDeterminer = 0;
        highLowDeterminer = ((myData->encryptionKey >> 8) ^ (myData->encryptionKey) ^
                (oppData->encryptionKey >> 8) ^ (oppData->encryptionKey)) & 0x01;
        // If highLowDeterminer == TRUE highest guess goes first
        if (highLowDeterminer) {
            if (myData->guess > oppData->guess) {
                return TURN_ORDER_START;
            } else if (myData->guess == oppData->guess) {
                return TURN_ORDER_TIE;
            } else {
                return TURN_ORDER_DEFER;
            }
        }        // Lowest guess goes first
        else {
            if (myData->guess < oppData->guess) {
                return TURN_ORDER_START;
            } else if (myData->guess == oppData->guess) {
                return TURN_ORDER_TIE;
            } else {
                return TURN_ORDER_DEFER;
            }
        }
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,596
    Code:
            } else if (in == '*') {
                parserState = FIRST_CHECKSUM_HALF;
                parserIndex++;
                return PROTOCOL_PARSING_GOOD;
    You increment parserIndex without storing anything in parserPayload

    So you end up with a garbage character between your payload data and your checksum data.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Battleship program, two questions?
    By Sam Maiden in forum C Programming
    Replies: 1
    Last Post: 11-25-2014, 06:51 PM
  2. help with battleship program
    By howardqd in forum C++ Programming
    Replies: 12
    Last Post: 12-15-2010, 08:40 PM
  3. question on battleship program.
    By newbc in forum C Programming
    Replies: 0
    Last Post: 12-07-2010, 08:32 AM
  4. Help with a Battleship Program
    By HBlakeH in forum C Programming
    Replies: 1
    Last Post: 12-05-2010, 11:13 PM
  5. Battleship program
    By swgh in forum C++ Programming
    Replies: 4
    Last Post: 04-07-2008, 09:02 AM

Tags for this Thread