/******************************************************************/
/* ACM ICPC 2012-2013                                             */
/* Northeastern European Regional Contest                         */
/* St Petersburg - Barnaul - Tashkent - Tbilisi, December 2, 2012 */
/******************************************************************/
/* Problem F. Folding Snake Cube                                  */
/*                                                                */
/* Original idea         Roman Elizarov                           */
/* Problem statement     Roman Elizarov                           */
/* Test set              Roman Elizarov                           */
/******************************************************************/
/* Checker                                                        */
/*                                                                */
/* Author                Roman Elizarov                           */
/******************************************************************/

import ru.ifmo.testlib.Checker;
import ru.ifmo.testlib.InStream;
import ru.ifmo.testlib.Outcome;

/**
 * Checker for NEERC'2012 Problem F: Folding Snake Cube
 * @author Roman Elizarov
 */
public class Check implements Checker {
    private static final int N = 3;
    private static final int N3 = N * N * N;

    private static final int K = 15;

    private static final int REQUIRED_LINE_LEN = 11;

    private static final int[] DX = {1, -1, 0, 0, 0, 0};
    private static final int[] DY = {0, 0, 1, -1, 0, 0};
    private static final int[] DZ = {0, 0, 0, 0, 1, -1};

    char[][] inLayout = new char[K][];
    StringBuilder seqIn = new StringBuilder();

    char[][][] outLayout = new char[N][N][N];
    StringBuilder seqOut = new StringBuilder();

    public Outcome test(InStream inf, InStream ouf, InStream ans) {
        read(inf);
        resolve();
        parse(ouf);
        unsolve();
        if (!seqOut.toString().equals(seqIn.toString()))
            throw new Outcome(Outcome.Type.WA, String.format("Layout has wrong sequence '%s', expected '%s'", seqOut, seqIn));
		return new Outcome(Outcome.Type.OK, String.format("Layout '%s'", seqOut));
	}

    void read(InStream inf) {
        for (int i = 0; i < K; i++) {
            inLayout[i] = inf.nextLine().toCharArray();
            assert inLayout[i].length == K;
        }
    }

    void resolve() {
        int x = -1;
        int y = -1;
        char c = code(0);
    start:
        for (x = 0; x < K; x++)
            for (y = 0; y < K; y++)
                if (inLayout[x][y] == c)
                    break start;
        int d = findDir2d(x, y, code(1));
        for (int i = 2; i < N3; i++) {
            x += DX[d];
            y += DY[d];
            int dd = findDir2d(x, y, code(i));
            seqIn.append(dd == d ? 'S' : 'T');
            d = dd;
        }
    }

    int findDir2d(int x, int y, char c) {
        for (int d = 0; d < 4; d++) {
            int xx = x + DX[d];
            int yy = y + DY[d];
            if (xx < 0 || xx >= K || yy < 0 || yy >= K)
                continue;
            if (inLayout[xx][yy] == c)
                return d;
        }
        throw new IllegalArgumentException("Cannot find " + c);
    }

    char code(int i) {
        return i % 2 == 0 ? (char)(i / 2 + 'A') : (char)(i / 2 + 'a');
    }

    private void parse(InStream ouf) {
        for (int x = 0; x < N; x++) {
            String line = ouf.nextLine();
            if (line.length() != REQUIRED_LINE_LEN)
                throw new Outcome(Outcome.Type.PE, String.format("Wrong line length %d, expected %d", line.length(), REQUIRED_LINE_LEN));
            for (int i = 1; i < N; i++) {
                char c = line.charAt(i * (N + 1) - 1);
                if (c != ' ')
                    throw new Outcome(Outcome.Type.PE, String.format("Wrong separator: '%c'", c));
            }
            for (int y = 0; y < N; y++)
                for (int z = 0; z < N; z++) {
                    char c = line.charAt(y * (N + 1) + z);
                    if ((c < 'A' || c > 'N') && (c < 'a' || c > 'm'))
                        throw new Outcome(Outcome.Type.PE, String.format("Wrong character: '%c'", c));
                    outLayout[x][y][z] = c;
                }
        }
        if (!ouf.seekEoF())
            throw new Outcome(Outcome.Type.PE, "Extra data in output file");
    }

    void unsolve() {
        int x = -1;
        int y = -1;
        int z = -1;
        char c = code(0);
        boolean found = false;
    start:
        for (x = 0; x < N; x++)
            for (y = 0; y < N; y++)
                for (z = 0; z < N; z++)
                    if (outLayout[x][y][z] == c) {
                        found = true;
                        break start;
                    }
        if (!found)
            throw new Outcome(Outcome.Type.WA, String.format("Missing initial '%c'", c));
        int d = findDir3d(x, y, z, code(1));
        for (int i = 2; i < N3; i++) {
            x += DX[d];
            y += DY[d];
            z += DZ[d];
            int dd = findDir3d(x, y, z, code(i));
            if (dd == d)
                seqOut.append('S');
            else
                seqOut.append('T');
            d = dd;
        }
    }

    private int findDir3d(int x, int y, int z, char c) {
        for (int d = 0; d < 6; d++) {
            int xx = x + DX[d];
            int yy = y + DY[d];
            int zz = z + DZ[d];
            if (xx < 0 || xx >= N || yy < 0 || yy >= N || zz < 0 || zz >= N)
                continue;
            if (outLayout[xx][yy][zz] == c)
                return d;
        }
        throw new Outcome(Outcome.Type.WA, String.format("No adjacent '%c'", c));
    }
}

