print "squashed-circle" diamond

There's been a bit of a buzz about the Print-Diamond practice recently. I recall doing this a couple of years ago with Johannes Brodwall. In cyber-dojo naturally. We took a wrong turn and were making a thorough mess of it. I vividly recall Johannes saying:
This is too difficult. We're doing it wrong.
I love that. If it's difficult you're probably doing it wrong. We gave up and took a break. We got a really nice Indian take away. Then we went back to Print-Diamond. Very quickly we came up with a new idea. We imagined the diamond lying in the center of an x,y axis. The Print-Diamond of 'C' would therefore look like this:

       -2 -1  0 +1 +2

  -2    -  -  A  -  -    
  -1    -  B  -  B  -
   0    C  -  -  -  C
  +1    -  B  -  B  -
  +2    -  -  A  -  -


Viewed like this you can think of the Diamond as a sort of squashed circle with the A,B,C characters all lying on the circumference. From here it was a short step to this:
(-2..+2).map{|row| 
  (-2..+2).map{|col| 
    row.abs + col.abs == 2 ? 'X' : '-'
  }.join
}

which, when puts'd gives:
--X--
-X-X-
X---X
-X-X-
--X--

And we knew we were on our way.
Let's hear it for Indian Food Driven Development!

yet another interesting TDD episode

In the previous episode I described how a custom assert function declared a local array which I did not initialize.
static void assert_fizz_buzz(const char * expected, int n)
{
    char actual[16];
    ...
}

The effect of not initializing the array was that state from one test leaked into another test and I got an unexpectedly passing test. I fixed the problem by initializing the array.
static void assert_fizz_buzz(const char * expected, int n)
{
    char actual[16] = "";
    ...
}

The most recent episode (in cyber-dojo naturally) revolved around this same issue. This time I was redoing the roman numerals exercise (1 → "I", 2 → "II", etc) in C. My custom assert function started like this.
...
#define PRINT(s) print_string(#s, s)

static void print_string(const char * name, const char * s)
{
    printf("%10s: \"%s\"\n", name, s);
}

static void assert_to_roman(const char * expected, int n)
{
    char actual[32];
    to_roman(actual, sizeof actual, n);
    if (strcmp(expected, actual) != 0)
    {
        printf("to_roman(%d) FAILED\n", n);
        PRINT(expected);
        PRINT(actual);
        assert(false);
    }
}

Once again I failed to initialize the array. I'm a slow learner. This time the test failed unexpectedly! And the diagnostic was even more unexpected:
to_roman(1) FAILED
  expected: "I"
    actual: "I"

This is a less than ideal diagnostic! It seemed that strcmp and printf had differing opinions on what a string is! I fixed it by adding initialization.
...
static void assert_to_roman(const char * expected, int n)
{
    char actual[32] = "";
    to_roman(actual, sizeof actual, n);
    if (strcmp(expected, actual) != 0)
    {
        printf("to_roman(%d) FAILED\n", n);
        PRINT(expected);
        PRINT(actual);
        assert(false);
    }
}

After this the tests passed. This addressed the immediate problem but it did not address to the root cause. So I removed the initialization and (with a hat tip to Mr Jonathon Wakely) I reworked print_string to display the length of the string as well as an indication of the (un)printability of each character:
static void print_string(const char * name, const char * s)
{
    printf("%10s: \"%s\" %d ", name, s, (int)strlen(s));
    for (size_t i = 0; i != strlen(s); i++)
    {
         putchar(isprint(s[i]) ? 'P' : 'U');   
    }
    putchar('\n');
}

With this change the diagnostic became:
to_roman(1) FAILED
  expected: "I" 1 P
    actual: "I" 4 UUUP

Much better. Then I thought about initializing the array a bit more. I realized that initializing the array to the empty string was a poor choice since it masked a fault in the implementation of to_roman which did not start like this:
void to_roman(char buffer[], size_t size, int n)
{
    buffer[0] = '\0';
    ...
}

So I added that and reworked print_string as follows:
static void assert_to_roman(const char * expected, int n)
{
    char actual[32];
    memset(actual, '!', sizeof actual);
    to_roman(actual, sizeof actual, n);
    ...
}

And I was back to green :-)