/*
 * Solve Number Place Puzzle
 */

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

typedef struct {
    int x, y;
} xy;

int isize; /* 盤面の縦の大きさ */
int jsize; /* 盤面の横の大きさ */
int num; /* 当てはめる数値は 1 〜 num */
int nob; /* 同一数が入れない制約領域の総数 */

xy **block; /* 制約の表 */

int verbose; /* 途中経過を表示する? */

/* 表示用のテーブル */
char printtable[] = " 123456789ABCDEFG";

/* 盤面を表示 */

void printboard(int **board)
{
    int i, j;

    for (i=0; i<isize; i++) {
        for (j=0; j<jsize; j++) {
            printf("%c", printtable[board[i][j]]);
        }
        printf("\n");
    }
}

/* エラーが起きたら終了するmalloc */

void *malloc_check(size_t size)
{
    void *r;

    if ((r = malloc(size)) == NULL) {
        printf("Not Enough memory\n");
        exit(1);
    }
    return r;
}

/* 桝(x,y)にaを置けるか? */

int check(int **board, int x, int y, int a)
{
    int bn;
    int i, j, k, l;

    for (bn = 0; bn < nob; bn++) {
        for (k=0; k<num; k++) {
            i = block[bn][k].x;
            j = block[bn][k].y;
            if ((i == x) && (j == y)) {
                for (l=0; l<num; l++) {
                    if (l == k) continue;
                    i = block[bn][l].x;
                    j = block[bn][l].y;
                    if (board[i][j] == a) return 0;
                }
                break;
            }
        }
    }

    return 1;
}

void recur(int **board)
{
    int i, j, k;

    if (verbose == 1) printboard(board);

    /* 未定な桝を探す */
    for (i=0; i<isize; i++) {
        for (j=0; j<jsize; j++) {
            if (board[i][j] == 0) goto next;
        }
    }

    /* 解発見 */
    printf("solution found:\n");
    printboard(board);
    return;

next:
    /* 未定桝を仮決定して再帰 */
    for (k=1; k<=num; k++) {
        if (check(board, i, j, k)) {
            if (verbose == 1) {
                printf("We assume (%d,%d) is %c\n",i, j, printtable[k]);
            }
            board[i][j] = k;
            recur(board);
            board[i][j] = 0;
        }
    }
}

int char2bit(char c)
{
    if (c == '.') return 0;
    if (c > '9') return c - 'A' +10;
    return c - '0';
}

/* 先頭が#なら改行まで読み飛ばす */

void skip_comment(FILE *fp)
{
    int c;
    while (1) {
        c = getc(fp);
        if (c != '#') break;
        while (getc(fp) != '\n') ;
    }
    ungetc(c, fp);
    return;
}

/* 数値を読み込む */

int get_number(FILE *fp)
{
    int c, r;

    skip_comment(fp);
    r = 0;
    while (1) {
        c = getc(fp);
        if (!isdigit(c)) break;
        r = r * 10 + c - '0';
    }
    ungetc(c, fp);
    return r;
}

int get_tmpstring(char **s, FILE *fp)
{
    int i, j;

    for (i=0; i<isize; i++) {
        skip_comment(fp);
        for (j=0; j<jsize; j++) {
            s[i][j] = getc(fp);
        }
        if (getc(fp) != '\n') return -1;
    }
    return 0;
}


int main(int argc, char **argv)
{
    int i, j, k;
    int count;
    int **board;
    char **tmpstring;
    FILE *fp;

    fp = NULL;
    verbose = 0;

    for (i=1; i<argc; i++) {
        if (argv[i][0] != '-') {
            if (fp != NULL) {
                printf("usage %s [-v] datafile\n", argv[0]);
                exit(1);
            }
            fp = fopen(argv[i], "r");
            if (fp == NULL) {
                printf("can't open %s\n", argv[1]);
                exit(1);
            }
        } else {
            switch(argv[i][1]) {
            case 'v':
                verbose = 1;
                break;
            default:
                printf("usage %s [-v] datafile\n", argv[0]);
                exit(1);
            }
        }
    }

    isize = get_number(fp);
    if (getc(fp) != '\n') { printf("data error\n"); exit(1); }
    jsize = get_number(fp);
    if (getc(fp) != '\n') { printf("data error\n"); exit(1); }
    num = get_number(fp);
    if (getc(fp) != '\n') { printf("data error\n"); exit(1); }
    nob = get_number(fp);
    if (getc(fp) != '\n') { printf("data error\n"); exit(1); }
    

    tmpstring = (char **)malloc_check(sizeof(char *) * isize);
    for (i=0; i<isize; i++) {
        tmpstring[i] = (char *)malloc_check(sizeof(char) * jsize);
    }

    board = (int **)malloc_check(sizeof(int *) * isize);
    for (i=0; i<isize; i++) {
        board[i] = (int *)malloc_check(sizeof(int) * jsize);
    }

    block = (xy **)malloc_check(sizeof(xy *) * nob);
    for (i=0; i<nob; i++) {
        block[i] = (xy *)malloc_check(sizeof(xy) * num);
    }


    if (get_tmpstring(tmpstring, fp) == -1) {
        printf("data error\n"); exit(1);
    }
    for (i=0; i<isize; i++) {
        for (j=0; j<jsize; j++) {
            board[i][j] = char2bit(tmpstring[i][j]);
        }
    }

    for (k=0; k<nob; k++) {
        if (get_tmpstring(tmpstring, fp) == -1) {
            printf("data error\n"); exit(1);
        }
        count = 0;
        for (i=0; i<isize; i++) {
            for (j=0; j<jsize; j++) {
                if (tmpstring[i][j] == '+') {
                    if (count >= num) {
                        printf("data error\n"); exit(1);
                    }
                    block[k][count].x = i;
                    block[k][count].y = j;
                    count++;
                }
            }
        }
        if (count != num) printf("insufficient constraint\n");
    }

    recur(board);

    for (i=0; i<isize; i++) free(tmpstring[i]);
    free(tmpstring);
    for (i=0; i<isize; i++) free(board[i]);
    free(board);
    for (i=0; i<nob; i++) free(block[i]);
    free(block);

    fclose(fp);

    return 0;
}
