#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;
}