/* create_lookup: Output contents of a lookup table for a 4x4 block in Conway's Life.
 * Usage: create_lookup <template name>, where <template name> is ul, ur, ll, or lr,
 * specifying which corner this lookup is for and thus how the bits are arranged.
 * The 2x2 lookup result will be placed in the appropriate bits for each corner
 * (ul: 0,1,4,5, ur: 2,3,6,7, ll: 8,9,12,13, lr: 10,11,14,15). Therefore the lookup
 * tables for ll and lr will have 16 bit entries. All extra bits are set to 0.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "create_lookup.h"
#include "util.h"

/* These templates specify how the bits of the short int are arranged within
 * each look-up table.
 */
template_type templates[] = {
    { "ul",  0, {{15, 12, 13, 14},
                 { 3,  0,  1,  2},
                 { 7,  4,  5,  6},
                 {11,  8,  9, 10}}
    },
    { "ur",  2, {{13, 14, 15, 12},
                 { 1,  2,  3,  0},
                 { 5,  6,  7,  4},
                 { 9, 10, 11,  8}}
    },
    { "ll",  8, {{ 7,  4,  5,  6},
                 {11,  8,  9, 10},
                 {15, 12, 13, 14},
                 { 3,  0,  1,  2}}
    },
    { "lr", 10, {{ 5,  6,  7,  4},
                 { 9, 10, 11,  8},
                 {13, 14, 15, 12},
                 { 1,  2,  3,  0}}
    }
};

int main(int argc, char* argv[])
{
    int i;

    set_prog_name(PROG);
    if (argc != 2)
        usage_abort();
    for (i=0; i < NUM_TEMPLATES; i++) {
        if (STR_EQUAL(argv[1], templates[i].name))
            break;
    }
    if (i == NUM_TEMPLATES)
        usage_abort();
    process(argv[1], &templates[i]);

    return 0;
}

void process(const char* name, template_type* template)
{
    FILE*        f;
    int          shiftage;
    int          field_len;
    int          num_cols;
    int          max;
    const char*  result_type;
    char         temp[64];
    int          cage[4][4];
    int          ncage[4][4];
    int          i, j, k;
    int          col;
    int          bit;
    int          neighbors;
    int          result;

    shiftage = template->shiftage;
    result_type = (shiftage < 8 ? "uint8" : "uint16");
    max = (1 << (shiftage+6)) - 1;
    sprintf(temp, "%u", max);
    field_len = strlen(temp);
    num_cols = 75 / (field_len + 2);

    sprintf(temp, "%s_lookup.c", name);
    f = fopen(temp, "w");
    if (!f)
        sys_error_abort("can't open %s for writing", temp);
    fprintf(f, "#include \"util.h\"\n\n");
    fprintf(f, "%s %s_lookup[0x10000] = {\n", result_type, name);

    col = 0;
    for (i=0; i < 0x10000; i++) {
        if (col == 0)
            fprintf(f, "    ");
        for (j=0; j < 4; j++) {
            for (k=0; k < 4; k++) {
                bit = template->bits[j][k];
                cage[j][k] = (i >> bit) & 1;
            }
        }
        memcpy(ncage, cage, 16*sizeof(int));
        for (j=1; j <= 2; j++) {
            for (k=1; k <= 2; k++) {
                neighbors = cage[j-1][k] + cage[j+1][k] + cage[j][k-1] + cage[j][k+1] +
                    cage[j-1][k-1] + cage[j-1][k+1] + cage[j+1][k-1] + cage[j+1][k+1];
                if (!cage[j][k] && neighbors == 3)
                    ncage[j][k] = 1;
                else if (cage[j][k] && neighbors != 2 && neighbors != 3)
                    ncage[j][k] = 0;
            }
        }
        result = (ncage[1][1]) + (ncage[1][2] << 1) + (ncage[2][1] << 4) +
                 (ncage[2][2] << 5);
        result <<= shiftage;
        fprintf(f, "%*u", field_len, result);
        if (i < 0xFFFF) {
            putc(',', f);
            col++;
            if (col == num_cols) {
                col = 0;
                putc('\n', f);
            }
            else
                putc(' ', f);
        }
        else
            putc('\n', f);
    }

    fprintf(f, "};\n");
}

void usage_abort(void)
{
    fprintf(stderr, "Usage: create_lookup <ul|ur|ll|lr>\n");
    exit(1);
}
