#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
#define KING 'n'
#define QUEEN 'e'
#define ROOK 'o'
#define BISHOP 's'
#define KNIGHT 'i'
#define PAWN 'w'
#define N 66             //max number of vertices in one part
#define INF 100000000    //just infinity
using namespace std;
void GetStr(char* res){
    char c;
    while(1){
        c=getchar_unlocked();
        if(c==' ' || c=='\n') continue;
        else break;
    }
    *res=c; res++;
    while(1){
        c=getchar_unlocked();
        if (c==' ' || c=='\n' || c==EOF) break;
        *res=c; res++;
    }
    *res='\0';
}
 
int GetInt(){
    int r=0;
    char c;
    while(1){
        c=getchar_unlocked();
        if(c==' ' || c=='\n') continue;
        else break;
    }
    r=c-'0';
    while(1){
        c=getchar_unlocked();
        if(c>='0' && c<='9') r=10*r+c-'0';
        else break;
    }
    return r;
}
 
vector <pair<int, int> > knightStep,bishopStep[4],listMagic;
 
queue < pair <int,int> > q;
int cost[N][N];          	//cost matrix
int n, max_match;        	//n workers and n jobs
int lx[N], ly[N];        	//labels of X and Y parts
int xy[N];               	//xy[x] - vertex that is matched with x,
int yx[N];               	//yx[y] - vertex that is matched with y
bool S[N], T[N];         	//sets S and T in algorithm
int slack[N];            	//as in the algorithm description
int slackx[N];           	//slackx[y] such a vertex, that
                         	// l(slackx[y]) + l(y) - w(slackx[y],y) = slack[y]
int _PREV[N];             	//array for memorizing alternating paths
 
int ans_cost,ans_tile;
 
void initStep(){
	
	bishopStep[1].pb(mp(1,1));// 4'clock 
	bishopStep[1].pb(mp(2,2));
	bishopStep[1].pb(mp(3,3));
	bishopStep[1].pb(mp(4,4));
	bishopStep[1].pb(mp(5,5));
	bishopStep[1].pb(mp(6,6));
	bishopStep[1].pb(mp(7,7));
	bishopStep[1].pb(mp(8,8));
	bishopStep[0].pb(mp(-1,-1)); //10'clock
	bishopStep[0].pb(mp(-2,-2));
	bishopStep[0].pb(mp(-3,-3));
	bishopStep[0].pb(mp(-4,-4));
	bishopStep[0].pb(mp(-5,-5));
	bishopStep[0].pb(mp(-6,-6));
	bishopStep[0].pb(mp(-7,-7));
	bishopStep[0].pb(mp(-8,-8));
	bishopStep[3].pb(mp(1,-1));// 7'clock 
	bishopStep[3].pb(mp(2,-2));
	bishopStep[3].pb(mp(3,-3));
	bishopStep[3].pb(mp(4,-4));
	bishopStep[3].pb(mp(5,-5));
	bishopStep[3].pb(mp(6,-6));
	bishopStep[3].pb(mp(7,-7));
	bishopStep[3].pb(mp(8,-8));
	bishopStep[2].pb(mp(-1,1)); //1'clock
	bishopStep[2].pb(mp(-2,2));
	bishopStep[2].pb(mp(-3,3));
	bishopStep[2].pb(mp(-4,4));
	bishopStep[2].pb(mp(-5,5));
	bishopStep[2].pb(mp(-6,6));
	bishopStep[2].pb(mp(-7,7));
	bishopStep[2].pb(mp(-8,8));
	
	knightStep.pb(mp(2,1));
	knightStep.pb(mp(2,-1));
	knightStep.pb(mp(-2,1));
	knightStep.pb(mp(-2,-1));
	knightStep.pb(mp(1,2));
	knightStep.pb(mp(1,-2));
	knightStep.pb(mp(-1,2));
	knightStep.pb(mp(-1,-2));
}
 
void init_labels()
{
    memset(lx, 0, sizeof(lx));
    memset(ly, 0, sizeof(ly));
    for (int x = 0; x < n; x++)
        for (int y = 0; y < n; y++)
            lx[x] = max(lx[x], cost[x][y]);
}
 
void add_to_tree(int x, int prevx) 
//x - current vertex,prevx - vertex from X before x in the alternating path,
//so we add edges (prevx, xy[x]), (xy[x], x)
{
    S[x] = true;                    //add x to S
    _PREV[x] = prevx;                //we need this when augmenting
    for (int y = 0; y < n; y++)    //update slacks, because we add new vertex to S
        if (lx[x] + ly[y] - cost[x][y] < slack[y])
        {
            slack[y] = lx[x] + ly[y] - cost[x][y];
            slackx[y] = x;
        }
}
 
void update_labels()
{
    int x, y, delta = INF;             //init delta as infinity
    for (y = 0; y < n; y++)            //calculate delta using slack
        if (!T[y])
            delta = min(delta, slack[y]);
    for (x = 0; x < n; x++)            //update X labels
        if (S[x]) lx[x] -= delta;
    for (y = 0; y < n; y++)            //update Y labels
        if (T[y]) ly[y] += delta;
    for (y = 0; y < n; y++)            //update slack array
        if (!T[y])
            slack[y] -= delta;
}
 
void augment()                         //main function of the algorithm
{
    if (max_match == n) return;        //check wether matching is already perfect
    int x, y, root;                    //just counters and root vertex
    int q[N], wr = 0, rd = 0;          //q - queue for bfs, wr,rd - write and read
                                       //pos in queue
    memset(S, false, sizeof(S));       //init set S
    memset(T, false, sizeof(T));       //init set T
    memset(_PREV, -1, sizeof(_PREV));    //init set _PREV - for the alternating tree
    for (x = 0; x < n; x++)            //finding root of the tree
        if (xy[x] == -1)
        {
            q[wr++] = root = x;
            _PREV[x] = -2;
            S[x] = true;
            break;
        }
 
    for (y = 0; y < n; y++)            //initializing slack array
    {
        slack[y] = lx[root] + ly[y] - cost[root][y];
        slackx[y] = root;
    }
	//second part of augment() function
    while (true)                                                        //main cycle
    {
        while (rd < wr)                                                 //building tree with bfs cycle
        {
            x = q[rd++];                                                //current vertex from X part
            for (y = 0; y < n; y++)                                     //iterate through all edges in equality graph
                if (cost[x][y] == lx[x] + ly[y] &&  !T[y])
                {
                    if (yx[y] == -1) break;                             //an exposed vertex in Y found, so
                                                                        //augmenting path exists!
                    T[y] = true;                                        //else just add y to T,
                    q[wr++] = yx[y];                                    //add vertex yx[y], which is matched
                                                                        //with y, to the queue
                    add_to_tree(yx[y], x);                              //add edges (x,y) and (y,yx[y]) to the tree
                }
            if (y < n) break;                                           //augmenting path found!
        }
        if (y < n) break;                                               //augmenting path found!
 
        update_labels();                                                //augmenting path not found, so improve labeling
        wr = rd = 0;                
        for (y = 0; y < n; y++)        
        //in this cycle we add edges that were added to the equality graph as a
        //result of improving the labeling, we add edge (slackx[y], y) to the tree if
        //and only if !T[y] &&  slack[y] == 0, also with this edge we add another one
        //(y, yx[y]) or augment the matching, if y was exposed
            if (!T[y] &&  slack[y] == 0)
            {
                if (yx[y] == -1)                                        //exposed vertex in Y found - augmenting path exists!
                {
                    x = slackx[y];
                    break;
                }
                else
                {
                    T[y] = true;                                        //else just add y to T,
                    if (!S[yx[y]])    
                    {
                        q[wr++] = yx[y];                                //add vertex yx[y], which is matched with
                                                                        //y, to the queue
                        add_to_tree(yx[y], slackx[y]);                  //and add edges (x,y) and (y,
                                                                        //yx[y]) to the tree
                    }
                }
            }
        if (y < n) break;                                               //augmenting path found!
    }
 
    if (y < n)                                                          //we found augmenting path!
    {
        max_match++;                                                    //increment matching
        //in this cycle we inverse edges along augmenting path
        for (int cx = x, cy = y, ty; cx != -2; cx = _PREV[cx], cy = ty)
        {
            ty = xy[cx];
            yx[cy] = cx;
            xy[cx] = cy;
        }
        augment();                                                      //recall function, go to step 1 of the algorithm
    }
}//end of augment() function
 
int hungarian()
{
    int ret = 0;                      //weight of the optimal matching
    max_match = 0;                    //number of vertices in current matching
    memset(xy, -1, sizeof(xy));    
    memset(yx, -1, sizeof(yx));
    init_labels();                    //step 0
    augment();                        //steps 1-3
	ans_cost = ans_tile = 0;
    for (int x = 0; x < n; x++) {      //forming answer there
		if(cost[x][xy[x]]!=-INF){
			ans_cost -= cost[x][xy[x]];
			ans_tile ++;
		}
	}
    return ret;
}
 
//king n
//queen e
//rook o 
//bishop s
//knight i
//pawn w
 
 
int main(){
	int magic[N][N],flag[N][N],x,y,p,l,step,_x,_y,t;
	char type,temp[15];
	vector < pair<	 int,pair<int,char> > > data;
	initStep();
	t=GetInt();
	//scanf("%d",&t);
	for(int tt=1;tt<=t;tt++){
		data.clear();
		listMagic.clear();
		memset(magic,-1,sizeof(magic));
		memset(flag,-1,sizeof(flag));
		p=GetInt();
		l=GetInt();
		for(int i=0;i<p;i++){
			x=GetInt();
			y=GetInt();
			GetStr(temp);
			data.pb(mp(x,mp(y,temp[2])));
		}
		for(int i=0;i<l;i++){
			x=GetInt();
			y=GetInt();
			magic[x][y]=i;
			listMagic.pb(mp(x,y));
		}
		x = max(p,l);
		n = x;
		for(int i=0;i<x;i++){
			for(int j=0;j<x;j++)cost[i][j]=-INF;
		}
		for(int i=0;i<3;i++){
		    for(int j=0;j<5;j++){
		        printf("Elem [%d][%d] = %d\n", i, j, cost[i][j]);
		    }
}
		for(int i=0;i<p;i++){
			type =  data[i].second.second;
			x = data[i].first;
			y = data[i].second.first;
			if(type==KING){
				for(int j=0;j<l;j++){
					_x = abs(x-listMagic[j].fi);
					_y = abs(y-listMagic[j].sc);
					cost[i][j] = -(_x + _y-min(_x,_y));
				}
			}
			else if(type==PAWN){
				for(int j=0;j<l;j++){
					if(listMagic[j].sc!=y) continue;
					_x = abs(x-listMagic[j].fi);
					cost[i][j] = -_x;
				}
			}
			else if(type==ROOK){
				for(int j=0;j<l;j++){
					cost[i][j] = 0;
					if(listMagic[j].sc!=y)cost[i][j]--;
					if(listMagic[j].fi!=x)cost[i][j]--;
				}				
			}
			else if(type==QUEEN){
				for(int j=0;j<l;j++){
					_x = abs(x-listMagic[j].fi);
					_y = abs(y-listMagic[j].sc);
					if(_x+_y == 0)cost[i][j] = 0;
					else if(_x==_y || _x == 0 || _y == 0) cost[i][j] = -1;
					else cost[i][j] = -2;
				}
			}
			else if(type==BISHOP){
				for(int j=0;j<l;j++){
					_x = abs(x-listMagic[j].fi);
					_y = abs(y-listMagic[j].sc);
					if(_x+_y == 0)cost[i][j] = 0;
					else if(_x==_y) cost[i][j] = -1;
					else  if((_x+_y)%2==0)cost[i][j] = -2;
				}
			}
			else{
				q.push(mp(x,y));
				step=0;
				while(!q.empty()){
					for(int j=q.size();j--;){
						x = q.front().first;
						y = q.front().second;
						q.pop();
						if(flag[x][y]!=i){
							flag[x][y]=i;
							if(magic[x][y]>=0)
								cost[i][magic[x][y]] = step*-1;
								for(int k = 0;k<knightStep.size();k++){
									_x = x + knightStep[k].fi;
									_y = y + knightStep[k].sc;
									if( _x>=1 && _x<=8 && _y>=1 && _y<=8 ){
										if(flag[_x][_y]!=i){
											q.push(mp(_x,_y));
										}
									}
								}
						
						}
						
					}
					step++;
				}
			}
			printf("Iteration %d\n", i);
		for(int i=0;i<3;i++){
		    for(int j=0;j<5;j++){
		        printf("Elem [%d][%d] = %d\n", i, j, cost[i][j]);
		    }
		}
		}
		hungarian();
		printf("Case %d: Secret reveals after moving %d pieces with minimum number of moves %d.\n",tt,ans_tile,ans_cost);
	}
	return 0; 
}
