Problem:
立方体の作品

芸術家品川は n 点の作品を出展するように依頼されました。そこで、立方体の 6 面をペンキで色付けしたものを作品として出展することにしました。作品は、Red、Yellow、Blue、Magenta、Green、Cyan の 6 色全てが使われていて、各面は 1 色で塗りつぶされています。品川は形が同じ立方体の作品でも色の配置の仕方を変え、異なる作品として n 点作成しました。

彼の友人であるあなたは、友人のよしみで作品を出展前に閲覧させてもらいましたが、そこであることに気が付きました。それらの作品の中に異なる色付けをされているように見えても、実は同じ色の組み合わせをした立方体が存在していたのです。このままでは、 n 点の作品を出展することできなくなってしまいます。

作成した作品の数と各作品の色の情報を入力とし、出展するためにあと何点必要かを出力するプログラムを作成してください。

立方体の各面の色は c1 から c6 までの記号で表され、 以下のような配置となっています。また、c1 から c6 のそれぞれは Red、Yellow、Blue、Magenta、Green、Cyan のいずれか 1 色となります。

Input

複数のデータセットの並びが入力として与えられます。 入力の終わりはゼロひとつの行で示されます。
各データセットは以下の形式で与えられます。

n
cube1
cube2
:
cuben

１行目に作品の数 n (1 ≤ n ≤ 30)、続く n 行に i 番目の作品の情報が与えられます。各作品の情報は次の形式で与えられます。

c1 c2 c3 c4 c5 c6

作品の色の配置 ci が空白区切りで与えられます。

データセットの数は 100 を超えません。

Output

データセットごとに、出展するのにあと何点の作品が必要かを１行に出力します。

Sample Input

3
Cyan Yellow Red Magenta Green Blue
Cyan Yellow Red Magenta Green Blue
Red Yellow Magenta Blue Green Cyan
4
Red Magenta Blue Green Yellow Cyan
Red Yellow Magenta Blue Green Cyan
Magenta Green Red Cyan Yellow Blue
Cyan Green Yellow Blue Magenta Red
0

Output for the Sample Input

1
1

Solution in C++ (judge verdict: Wrong Answer)

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<cmath>
#include<sstream>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<utility>
#include<iomanip>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<list>
#include<set>
#include<stdlib.h>
#include<time.h>
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define repp(i,k,n) for(int i=k;i<(int)n;i++)
using namespace std;
const int dx[4] = { 0, 1, 0, -1 }, dy[4] = { 1, 0, -1, 0 };
const int dX[8] = { 0, 1, 1, 1, 0, -1, -1, -1 }, dY[8] = { 1, 1, 0, -1, -1, -1, 0, 1 };
struct XY
{
	int x;
	int y;
};
vector<long long> Prime;
void SieveOfEratosthenes(long long e) //setup vector<long long>Prime(~x)
{
	bool *x=new bool[e];
	for (long long i = 0; i <= e; i++)x[i] = false;
	for (long long i = 2; i <= e; i++)
	{
		if (x[i]);
		else
		{
			Prime.push_back(i);
			for (long long l = i; l <= e; l += i)x[l] = true;
		}
	}
	return;
}
int StringToInt(string a)
{
	stringstream ss;
	int x;
	ss << a;
	ss >> x;
	return x;
}
string IntToString(int a)
{
	stringstream ss;
	string x;
	ss << a;
	ss >> x;
	return x;
}
int GetRandom(int MIN, int MAX)
{
	static int flag=0;
	if (flag == 0)
	{
		srand((unsigned int)time(NULL));
		flag = 1;
	}
	return MIN + (int)(rand()*(MAX - MIN + 1.0) / (1.0 + RAND_MAX));
}
int in()
{
	int x;
	cin >> x;
	return x;
}
void outl(string a)
{
	cout << a << endl;
	return;
}
void outl(int a)
{
	cout << a << endl;
	return;
}
void out(string a)
{
	cout << a;
	return;
}
void out(int a)
{
	cout << a;
	return;
}
/*
(char)'1' - (int)48 = (int)1;
???1111181
 (char)A=(int)65
 (char)a=(int)97
*/
////////////////////////////////////////////////////

int main()
{
	int n;
	while (cin >> n&&n)
	{
		int ans = 0;
		map<string, int> x;
		for (int i = 0; i < n; i++)
		{
			string z;
			int as = 1;
			for (int l = 0; l < 6; l++)
			{
				char now[10];
				cin >> now;
				z += now[0];
			}
			for (int q = 0; q < 6; q++)
			{
				for (int i = 0; i < 4; i++)
				{
					if (x.count(z))as = 0;
					swap(z[4], z[3]);
					swap(z[4], z[1]);
					swap(z[4], z[2]);
				}
				string nn;
				nn += z[5];
				rep(i, 5)nn += z[i];
				z = nn;
			}
			ans += as;
			for (int q = 0; q < 6; q++)
			{
				for (int i = 0; i < 4; i++)
				{
					x[z] = 1;
					swap(z[4], z[3]);
					swap(z[4], z[1]);
					swap(z[4], z[2]);
				}
				string nn;
				nn += z[5];
				rep(i, 5)nn += z[i];
				z = nn;
			}
		}
		cout << n - ans << endl;
	}
}