re: Daily Challenge #29 - Xs and Os VIEW POST

TOP OF THREAD FULL DISCUSSION
re: C 😱 don't kill me please #include <stdio.h> #include <string.h> #include <stdbool.h> // bool as string #define BOOL_STR(b) b ?...
 

Is it allowed to modify someone else’s solution? I think you made it a bit more complicated than necessary. Anyone please correct me if I’m wrong:

  • C strings end with the null character '\0', so you can skip getting the string length and do a while loop that checks for the null character (strlen does just that anyway);

  • I didn’t really understand why you’re walking the string from the start and the middle, instead of from beginning to end, so I changed it;

  • since we then only test for x and o once, I could inline the tests;

  • xc == oc and d == 88 || d == 120 are already boolean expressions, so you don’t need the ternary operator ... ? true : false or an if(...) return true; else return false;;

  • since I never used assertions in C, I took the opportunity to try them for the test cases (I intentionally wrote assert(count_xo("xooxx") == false) in the tests instead of assert(! count_xo("xooxx")) for consistency and readability.

#include <stdio.h>
#include <stdbool.h>

// bool as string
#define BOOL_STR(b) b ? "true" : "false"

static bool count_xo(const char* d){
    // null pointer
    if(!d) return true;
    // counters
    unsigned xc = 0, oc = 0, i = -1;
    while(d[++i] != '\0'){
        // X counter
        if( d[i] == 88 || d[i] == 120 ) xc++;
        // O counter
        if( d[i] == 79 || d[i] == 111 ) oc++;
    }
    // res
    return xc == oc;
}

int main(void) { 
    // test strings
    assert(count_xo("ooxx") == true);
    assert(count_xo("xooxx") == false);
    assert(count_xo("ooxXm") == true);
    assert(count_xo("zpzpzpp") == true);
    assert(count_xo("zzoo") == false);
    assert(count_xo("xoffxffo") == true);

    return 0; 
}
 

Hi and no problem changing the code

The following is indeed not needed:

(xc == oc ? true : false);

The loop tests strings from both sides to be more performant. Try doing benchmarks of both versions and post the results. I don't have time right now but might do it in the evening and show you the difference. Or, I might just embarrass myself lol.

Cheers

 

I wrote this too fast without even thinking too much, so once again, I appreciate your comment. Anyway, I know that inlining helps, but speed wasn't on my priority list for this challenge. :)

Here are my results:

Your code: ~550 nsec
My code: ~1140 nsec

Thumbs up for faster code.

P.S.
I suspected that strlen might be the culprit, and I was right.

If I change the code like this, I get results similar to yours, around 500 nsec more/less

static bool count_xo(const char* d, size_t l){
    // null pointer
    if(!d) return true;
    // no data
    if(!l) return true;
    // res counters
    unsigned xc = 0, oc = 0;
    // mid point
    unsigned mp = l / 2, rm = l % 2;
    // check for 88 (X) and 79 (O)
    // O(N/2)
    for(unsigned i = 0, j = l - 1; i < mp; i++, j--){
        // X counter
        xc += check_x(d[i]) + check_x(d[j]);
        // O counter
        oc += check_o(d[i]) + check_o(d[j]);
    }
    // remainder
    if(rm){
        // X counter
        xc += check_x(d[mp + 1]);
        // O counter
        oc += check_o(d[mp + 1]);
    }

    // res
    return xc == oc;
}

Nice. I didn’t inline for speed, but for compactness, so that people don’t say C is too complicated, so verbose, etc. :-)

C is my baby, just started embedded C on SBCs, mostly arm 32bit. And people will always say that 🤣👍

code of conduct - report abuse