// spj16.cpp — SYZOJ SPJ for 16x16 Hexadoku.
//
// SYZOJ SPJ protocol (see /opt/syzoj/judge/src/runner/judge.ts:runSpj):
//   - SPJ runs with no command-line arguments.
//   - cwd is spjWorkingDir, which contains:
//       input       — the test-case input file
//       user_out    — the contestant's output
//   - SPJ writes a numeric score to stdout, redirected to 'score.txt'.
//     Score 100 == AC, 0 == WA. Anything in [0,100] is Partially Correct.
//   - SPJ writes a diagnostic message to stderr, redirected to 'message.txt'.
//
// Semantics: the contestant's output is AC iff every puzzle is a legal
// 16x16 Hexadoku solution that respects the given hints (any of possibly
// many solutions is accepted). We do NOT compare against a reference,
// because puzzles with fewer clues have multiple valid completions.
#include <bits/stdc++.h>
using namespace std;

static const int N = 16, CELLS = 256, BOX = 4;

static int val(char ch) {
    if (ch >= '0' && ch <= '9') return ch - '0';
    if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10;
    return -1;  // 'x' = empty
}

static string slurp(const char *path) {
    ifstream f(path, ios::binary);
    string s((istreambuf_iterator<char>(f)), istreambuf_iterator<char>());
    if (!s.empty() && s.back() == '\n') s.pop_back();
    return s;
}

int main() {
    string inp = slurp("input");
    string uop = slurp("user_out");

    // Tokenize input into lines.
    vector<string> il;
    {
        size_t st = 0;
        for (size_t i = 0; i <= inp.size(); i++) {
            if (i == inp.size() || inp[i] == '\n') {
                il.push_back(inp.substr(st, i - st));
                st = i + 1;
            }
        }
    }
    if (il.empty()) {
        fprintf(stderr, "empty input\n");
        puts("0"); return 0;
    }
    int T = atoi(il[0].c_str());
    if (T <= 0) {
        fprintf(stderr, "bad T: %s\n", il[0].c_str());
        puts("0"); return 0;
    }

    // Tokenize user output into lines.
    vector<string> ul;
    {
        size_t st = 0;
        for (size_t i = 0; i <= uop.size(); i++) {
            if (i == uop.size() || uop[i] == '\n') {
                ul.push_back(uop.substr(st, i - st));
                st = i + 1;
            }
        }
    }
    while (!ul.empty() && ul.back().empty()) ul.pop_back();

    int line_off = 0;
    for (int t = 0; t < T; t++) {
        int row_start = 1 + t * 17;  // 16 rows + 1 blank between puzzles

        // Check size: need exactly 16 lines per puzzle.
        if ((int)ul.size() < line_off + N) {
            fprintf(stderr, "puzzle %d: user_output too short (have %d lines, need %d more)\n",
                    t + 1, (int)ul.size() - line_off, N);
            puts("0"); return 0;
        }

        // Read hints into a 16x16 char array.
        char hint[N][N];
        bool any_hint = false;
        for (int r = 0; r < N; r++) {
            const string &row = il[row_start + r];
            for (int c = 0; c < N; c++) {
                char ch = c < (int)row.size() ? row[c] : '?';
                hint[r][c] = ch;
                if (ch != 'x' && ch != 'X' && val(ch) < 0) {
                    fprintf(stderr, "puzzle %d: invalid hint char '%c' at row %d col %d\n",
                            t + 1, ch, r, c);
                    puts("0"); return 0;
                }
                if (ch != 'x' && ch != 'X') any_hint = true;
            }
        }
        if (!any_hint) {
            fprintf(stderr, "puzzle %d: no hints\n", t + 1);
            puts("0"); return 0;
        }

        // Read user's output into a 16x16 char array.
        char out_[N][N];
        for (int r = 0; r < N; r++) {
            const string &row = ul[line_off + r];
            for (int c = 0; c < N; c++) {
                out_[r][c] = c < (int)row.size() ? row[c] : 0;
            }
        }

        // Check 1: every cell is a valid hex digit.
        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {
            if (val(out_[r][c]) < 0) {
                fprintf(stderr, "puzzle %d: invalid output char '%c' at row %d col %d\n",
                        t + 1, out_[r][c], r, c);
                puts("0"); return 0;
            }
        }

        // Check 2: hints are preserved.
        for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {
            char h = hint[r][c];
            if (h != 'x' && h != 'X' && out_[r][c] != h) {
                fprintf(stderr, "puzzle %d: hint mismatch at row %d col %d (hint '%c', got '%c')\n",
                        t + 1, r, c, h, out_[r][c]);
                puts("0"); return 0;
            }
        }

        // Check 3: each row is a permutation of 0..f.
        for (int r = 0; r < N; r++) {
            uint32_t seen = 0;
            for (int c = 0; c < N; c++) seen |= 1u << val(out_[r][c]);
            if (seen != 0xFFFFu) {
                fprintf(stderr, "puzzle %d: row %d not a permutation of 0..f\n", t + 1, r);
                puts("0"); return 0;
            }
        }
        // Check 4: each column is a permutation of 0..f.
        for (int c = 0; c < N; c++) {
            uint32_t seen = 0;
            for (int r = 0; r < N; r++) seen |= 1u << val(out_[r][c]);
            if (seen != 0xFFFFu) {
                fprintf(stderr, "puzzle %d: col %d not a permutation of 0..f\n", t + 1, c);
                puts("0"); return 0;
            }
        }
        // Check 5: each 4x4 box is a permutation of 0..f.
        for (int b = 0; b < N; b++) {
            int br = (b / BOX) * BOX, bc = (b % BOX) * BOX;
            uint32_t seen = 0;
            for (int dr = 0; dr < BOX; dr++) for (int dc = 0; dc < BOX; dc++) {
                seen |= 1u << val(out_[br + dr][bc + dc]);
            }
            if (seen != 0xFFFFu) {
                fprintf(stderr, "puzzle %d: box %d not a permutation of 0..f\n", t + 1, b);
                puts("0"); return 0;
            }
        }

        line_off += N;
        if (t != T - 1 && (int)ul.size() > line_off && ul[line_off].empty()) line_off++;
    }

    puts("100");
    return 0;
}