#include <ctype.h>

#include <iostream>
#include <vector>
#include <utility>
#include <queue>

using namespace std;

/* Maximum number of columns in hex grid (1, 2, 3, ...) */
#define COLS 9

/* Maximum number of rows in hex gid (A, B, C, ...) */
#define ROWS 9

/* Total number of movement points available */
#define MP 10

/* Movement cost representing unreachable nodes */
#define MAXCOST (std::numeric_limits<int>::max())

/* A convenient way to represent a single coordinate */
typedef pair<int, int> point;

/* Insertion operator for printing coordinates as letter/number */
ostream &operator<<(ostream &s, point const &p)
{
    s << (char) ('A' + p.first) << p.second + 1;
    return s;
}

/* Extraction operator for parsing coordinates in letter/number format */
istream &operator>>(istream &s, point &p)
{
    char c;

    /* Parse row letter and convert to 0 based array index */
    cin >> c;
    p.first = c - 'A';
    
    /* Parse column number and convert to 0 based array index */
    cin >> p.second;
    p.second--;
    
    /* Verify input is correct */
    if(p.first < 0 || p.first >= ROWS || p.second < 0 || p.second >= COLS)
        throw "Invalid coordinate";
        
    return s;
}

/* Structure representing a single hex cell on the grid */
typedef struct {
    char terrain; /* Terrain type: U, W, F, H, or M */
    char unit;    /* Unit type occupying grid: G, S, M, or '\0' if none */
    char side;    /* 0 or 1 representing which side this unit is on */
    
    /* These fields are used by Dijkstra's algorithm in process_move() */
    char visited; /* True if this node has been visited already */
    point prev;   /* Coordinate of previous cell on path or (-1,-1) for start */
    int cost;     /* Tentative shortest path cost to this node */
} cell;

/* Array holding the representation of the entire hex grid */
cell grid[ROWS][COLS];

/*
 * Number of cells adjacent to any other given cell; i.e. the number of
 * different directions one can move to from a given cell.
 */
#define DIRS 6

/*
 * List of all possible directions that one can move to from a given cell
 * within the square array representation of a hexagonal grid. The directions
 * are specified as ( row_offset, col_offset ).
 */
point dir[] = {
    point(  0, -1 ),  /* Move left (E5 -> E4) */
    point(  0, +1 ),  /* Move right (E5 -> E6) */
    point( -1,  0 ),  /* Move up-left (E5 -> D5) */
    point( +1,  0 ),  /* Move down-right (E5 -> F5) */
    point( -1, +1 ),  /* Move up-right (E5 -> D6) */
    point( +1, -1 )   /* Move down-left (E5 -> F4) */
};

/*
 * Read in "length" characters from the input representing one row of the
 * hex grid. The array elements filled are grid[row][col], grid[row][col+1], 
 * etc, up to "length" number of times.
 */
void parse_row(int row, int col, int length)
{
    /* Iterate over all cells on this grid */
    for(; length; col++, length--) {
        char c;
        
        /* Read in the next terrain type */
        cin >> c;
        
        /* Verify terrain type is correct */
        if(c != 'U' && c != 'W' && c != 'H' && c != 'M' && c != 'F')
            throw "Invalid terrain type";
            
        /* Assign to correct grid location */
        grid[row][col].terrain = c;
    }
}

/* Read in the terrain layout */
void parse_grid(void)
{
    int row, col;

    /* Initialize all grid spaces to underwater terrain with no units present */
    for(row = 0; row < ROWS; row++) {
        for(col = 0; col < COLS; col++) {
            grid[row][col].terrain = 'U';
            grid[row][col].unit = 0;
        }
    }
        
    /*
     * Parse each row of the hex grid as it appears on each line of the input.
     * The hex grid is numbered starting with 1, but the C array starts with 0,
     * hence the explicit subtraction.
     */
    parse_row(0, 5 - 1, 5);
    parse_row(1, 4 - 1, 6);
    parse_row(2, 3 - 1, 7);
    parse_row(3, 2 - 1, 8);
    parse_row(4, 1 - 1, 9);
    parse_row(5, 1 - 1, 8);
    parse_row(6, 1 - 1, 7);
    parse_row(7, 1 - 1, 6);
    parse_row(8, 1 - 1, 5);
}

#ifdef DEBUG
/* Print out the grid array for debugging purposes */
void print_grid(void)
{
    int row, col;

    /* Print out column numbers */
    cout << "  ";
    for(col = 0; col < COLS; col++)
        cout << col + 1 << " ";        
    cout << endl;
    
    /* Iterate over each row */
    for(row = 0; row < ROWS; row++) {
    
        /* Print out row labels */
        cout << (char) ('A' + row) << " ";
    
        /* Iterate over each column */
        for(col = 0; col < COLS; col++) {
        
            /*
             * If a unit occupies the cell, print unit type in lower case
             * and number indicating which side the unit is on.
             */
            if(grid[row][col].unit) {
                cout << (char) tolower(grid[row][col].unit);
                cout << (int) grid[row][col].side;
            }
                
            /* Otherwise, print the terrain type in uppercase */
            else
                cout << grid[row][col].terrain << " ";
        }
        cout << endl;
    }
}

/* Print out the costs associated with moving to each cell for debug purposes */
void print_cost(void)
{
    int row, col;

    /* Print out column numbers */
    cout << "  ";
    for(col = 0; col < COLS; col++)
        cout << col + 1 << " ";        
    cout << endl;
    
    /* Iterate over each row */
    for(row = 0; row < ROWS; row++) {
    
        /* Print out row labels */
        cout << (char) ('A' + row) << " ";
    
        /* Iterate over each column */
        for(col = 0; col < COLS; col++) {
        
            /* If cell is unreachable print a dot */
            if(grid[row][col].cost == MAXCOST) {
                cout << ". ";
            }
                
            /* Otherwise, print out the cost */
            else {
                cout << grid[row][col].cost;
                
                /* Print an extra space if cost is only one digit */
                if(grid[row][col].cost < 10)
                    cout << " ";
            }
        }
        cout << endl;
    }
}
#endif

/* Parse unit lists for both sides and place units on board */
void parse_units(void)
{
    int side, count[2];
    
    /* Parse number of units present on each side */
    cin >> count[0] >> count[1];
    
    /* Parse the units for each side */
    for(side = 0; side < 2; side++) {
        int i;

        /* Parse each unit individually */
        for(i = 0; i < count[side]; i++) {
            char unit;
            point p;
            
            /* Parse unit type and location */
            cin >> unit >> p;
            
            /* Verify unit type is correct */
            if(unit != 'G' && unit != 'M' && unit != 'S')
                throw "Invalid unit type";
            
            /* Place unit on the board */
            grid[p.first][p.second].unit = unit;
            grid[p.first][p.second].side = side;            
        }
    }
}

/*
 * Given a cell position (row, col) and a unit type "unit" on the side "side"
 * passing through this cell position, return true if the adjecent cell in
 * direction "idx" contains a stronger unit of the opposing side.
 */
bool stronger(int row, int col, int idx, char unit, char side)
{
    /* The coordinate we are checking */
    point dest(row + dir[idx].first, col + dir[idx].second);

    /* Check if coordinate is on the map */
    if(dest.first < 0 || dest.second < 0 || dest.first >= ROWS || dest.second >= COLS)
        return false;
        
    /* The hex cell we are checking */
    cell &cell(grid[dest.first][dest.second]);
    
    /* Check if the cell has any unit or if it is a friendly unit */
    if(!cell.unit || cell.side == side)
        return false;
        
    /* If an enemy unit is present, check if it is stronger than this unit */
    if(cell.unit == 'G' && unit == 'S')
        return true;
    if(cell.unit == 'M' && unit == 'G')
        return true;
    if(cell.unit == 'S' && unit == 'M')
        return true;
        
    /* Otherwise, it must be a weaker or equal enemy unit */
    return false;
}

/*
 * Return cost for movement to position "dest". The "final" parameter
 * determines if this move is the last one or an intermediate move, and
 * therefore affects how the cost is calculated. If the move is not possible,
 * MAXCOST is returned. The "unit" and "side" arguments specify the type of
 * unit being moved and what side that unis it on--this affects the cost
 * calculation with respect to enemy units on the grid.
 */
int process_cost(point const &dest, bool final, char unit, char side)
{
    /* Check if moving off the edge of the grid */
    if(dest.first < 0 || dest.second < 0 || dest.first >= ROWS || dest.second >= COLS)
        return MAXCOST;
    
    /* The hex cell we are moving into */
    cell &cell(grid[dest.first][dest.second]);
            
    /* The final destination cell cannot be occupied by other units */
    if(final) {
        if(cell.unit)
            return MAXCOST;
    }
    
    /* Check costs specific to intermediate movement cells */
    else {
    
        /* Cannot move through cells occupied by enemy units */
        if(cell.unit && cell.side != side)
            return MAXCOST;
            
        /* Can't move if neighbors of destination cell have stronger units */
        for(int i = 0; i < DIRS; i++) {
            if(stronger(dest.first, dest.second, i, unit, side))
                return MAXCOST;
        }
    }
    
    /* Compute movement cost based on terrain type of destination cell */
    switch(cell.terrain) {
        case 'F':
            return 1;
        case 'W':
            return 2;
        case 'H':
            return 3;
        case 'M':
            return 4;
        case 'U':
            return MAXCOST;            
    };
    
    /* Should never reach here */
    return MAXCOST;
}

/* Comparison function object required for priority_queue in process_move() */
class cost_compare {
    public:
        inline bool operator()(point const &a, point const &b) const
        {
            cell &cell1 = grid[a.first][a.second];
            cell &cell2 = grid[b.first][b.second];

            return cell1.cost > cell2.cost;
        }
};

/* Process each move; return number of points left or -1 if move not possible */
int process_move(point start, point end)
{
    int row, col;
    
    /* Priority queue for picking the next least cost cell */
    priority_queue<point, vector<point>, cost_compare> queue;

    /* The cell containing the unit we want to move */
    cell &start_cell(grid[start.first][start.second]);

    /* Verify the starting position has a unit to move */
    if(!start_cell.unit)
        return MAXCOST;

    /* Initialize data needed by Dijkstra's algorithm */
    for(row = 0; row < ROWS; row++) {
        for(col = 0; col < COLS; col++) {
            grid[row][col].cost = MAXCOST;
            grid[row][col].visited = false;
            grid[row][col].prev = point(-1, -1);
        }
    }
    
    /* Setup start cell info as required by Dijkstra's algorithm */
    grid[start.first][start.second].cost = 0;
    queue.push(start);

    /* Keep running Dijkstra until all nodes are visited */
    while(!queue.empty()) {
        int i;
    
        /* Remove the closest cell from the priority queue */
        point cur_point = queue.top();
        queue.pop();
        
        /* Skip this cell if it has been already visited */
        cell &cur_cell = grid[cur_point.first][cur_point.second];
        if(cur_cell.visited)
            continue;
        
        /* Mark cell grid as visited */
        cur_cell.visited = true;
        
        /* Check all adjacent cells to this one */
        for(i = 0; i < DIRS; i++) {
            int cost;
            
            /* The coordinate of the adjacent cell */
            point adj_point(cur_point.first + dir[i].first,
                cur_point.second + dir[i].second);
            
            /* Calculate edge cost to adjacent cell */
            cost = process_cost(adj_point, (adj_point == end), start_cell.unit,
                start_cell.side);
            
            /* If node is reachable, compare actual cost to tentative cost */
            if(cost != MAXCOST) {
            
                /* The actual adjacent cell itself */
                cell &adj_cell = grid[adj_point.first][adj_point.second];
                
                /* Check if real cost is smaller than tentative cost */
                if(cur_cell.cost + cost < adj_cell.cost) {
                
                    /* Adjust tentative cost and enqueue adjacent cell */
                    adj_cell.cost = cur_cell.cost + cost;
                    adj_cell.prev = cur_point;
                    queue.push(adj_point);
                }
                
            }
        }
    }
    
#ifdef DEBUG

    /* Print out calculated costs for movement */
    cout << "Movement costs" << endl;
    print_cost();

    /* If debug output enabled, print out the path in reverse */
    cout << "Movement path (in reverse): ";
    point p(end);

    /* The start cell has a prev field of (-1, -1) */
    while(p != point(-1, -1)) {
        cout << p << " ";
        p = grid[p.first][p.second].prev;
    }
    
    cout << endl;
#endif

    /* Return computed cost to final destination node */
    return grid[end.first][end.second].cost;
}

/* Main body of program */
void process(void)
{
    int game_num, game_idx;
    
    /* Throw exceptions on unexpected EOF */
    cin.exceptions(ios::eofbit);
       
    /* Read how many games are to be analyzed */
    cin >> game_num;

    /* Process each puzzle separately */
    for(game_idx = 0; game_idx < game_num; game_idx++) {
        int i, moves;

        cout << "Game #" << game_idx + 1 << endl;
    
	/* Read in the terrain and unit layout */
        parse_grid();
        parse_units();
#ifdef DEBUG
        cout << "Initial grid" << endl;
        print_grid();
#endif
        
        /* Read in the number of moves to process */
        cin >> moves;
        
        /* Process each move and print the results */
        for(i = 0; i < moves; i++) {
            point start, end;
            int cost;
            
            /* Parse the start and end points for each move */
            cin >> start >> end;
            
            /* Calculate total cost of making the move */
            cost = process_move(start, end);

            /* Print out the move label */
            cout << "Move #" << i + 1 << " (" << start << " -> " << end << "): ";
                        
            /* Check if the cost is less than allowable movement points */
            if(cost <= MP) {
                cell &start_cell = grid[start.first][start.second];
                cell &end_cell = grid[end.first][end.second];
            
                /* Make the move for real on the grid */
                end_cell.unit = start_cell.unit;
                end_cell.side = start_cell.side;
                start_cell.unit = 0;
            
                cout << "Successful (" << MP - cost << " points left)" << endl;
#ifdef DEBUG
                print_grid();
#endif
            }
            
            /* Print a message if the move is not possible */
            else {
                cout << "Unsuccessful" << endl;
            }
        }        
    }    
}

/* Run program and print out any exceptions that occur */
int main(void)
{
    /* Run main body of code */
    try {
        process();
    }
    
    /* Catch any internally generated exceptions */
    catch(char const *e) {
        cerr << "Exception: " << e << endl;
    }
    
    /* Catch unexpected EOF on input */
    catch(ios::failure const &ee) {
        cerr << "Exception: Unexpected EOF on input" << endl;
    }
    
    return 0;
}