#define _USE_MATH_DEFINES
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<numeric>
#include<set>
#include<stack>
#include<string>
#include<sstream>
#include<queue>
#include<vector>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

#define MOD 1000000007
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL

#define EPS (1e-10)
#define equals(a,b) (fabs((a)-(b)) < EPS)

//0?¬?
class Point {
public:
	double x, y;

	Point(double x = 0, double y = 0) :x(x), y(y) {}

	Point operator+(Point p) { return Point(x + p.x, y + p.y); }
	Point operator-(Point p) { return Point(x - p.x, y - p.y); }
	Point operator*(double a) { return Point(a * x, a * y); }
	Point operator/(double a) { return Point(x / a, y / a); }
	bool operator<(const Point &p)const { return x != p.x ? x < p.x : y < p.y; }
	bool operator==(const Point &p)const { return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS; }

	double abs() { return sqrt(norm()); }
	double norm() { return x*x + y*y; }

	//Vector????????¢
	Point rotate(double rad) { return Point(x*cos(rad) - y*sin(rad), x*sin(rad) + y*cos(rad)); }
};
inline ostream &operator << (ostream &os, const Point &p) { os << p.x << " " << p.y; return os; }
inline istream &operator >> (istream &is, Point &p) { double x, y; is >> x >> y; p = Point(x, y); return is; }

//1?¬?
typedef Point Vector;

class Segment {
public:
	Point p1, p2;
	Segment(Point p1 = Point(), Point p2 = Point(1, 1)) :p1(p1), p2(p2) {}
	Vector vec() { return p2 - p1; }
};
typedef Segment Line;

//2?¬?
class Circle {
public:
	Point c; //center
	double r; //radius
	Circle(Point c = Point(), double r = 0.0) :c(c), r(r) {}
};
typedef vector<Point> Polygon;

//?????? dot product
double dot(Vector a, Vector b) { return a.x*b.x + a.y*b.y; }
//?????? cross product
double cross(Vector a, Vector b) { return a.x*b.y - a.y*b.x; }

//????????¢??? radian ??? ??? degree
double rad(double deg) { return M_PI*deg / 180; }
//????§? argument
double arg(Vector p) { return atan2(p.y, p.x); }
//?\???¢??? polar form
Vector polar(double r, double a) { return Point(cos(a)*r, sin(a)*r); }

//??´?????????
bool isOrthogonal(Vector a, Vector b) { return equals(dot(a, b), 0.0); }
bool isOrthogonal(Point a1, Point a2, Point b1, Point b2) { return isOrthogonal(a1 - a2, b1 - b2); }
bool isOrthogonal(Segment s1, Segment s2) { return equals(dot(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0); }

//????????????
bool isParallel(Vector a, Vector b) { return equals(cross(a, b), 0.0); }
bool isParallel(Point a1, Point a2, Point b1, Point b2) { return isParallel(a1 - a2, b1 - b2); }
bool isParallel(Segment s1, Segment s2) { return equals(cross(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0); }

//?°???±
Point project(Segment s, Point p) {
	Vector base = s.p2 - s.p1;
	double r = dot(p - s.p1, base) / base.norm();
	return s.p1 + base*r;
}
//????°?
Point reflect(Segment s, Point p) { return p + (project(s, p) - p)*2.0; }

//??????(p0,p1)????????????p2???????????¢???
enum { ONLINE_FRONT = -2, CLOCKWISE, ON_SEGMENT, COUNTER_CLOCKWISE, ONLINE_BACK };
int ccw(Point p0, Point p1, Point p2) {
	Vector a = p1 - p0, b = p2 - p0;
	if (cross(a, b) > EPS)return COUNTER_CLOCKWISE;
	if (cross(a, b) < -EPS)return CLOCKWISE;
	if (dot(a, b) < -EPS)return ONLINE_BACK; //p2 p0 p1
	if (a.norm() < b.norm())return ONLINE_FRONT; //p0 p1 p2
	return ON_SEGMENT;
}

//??´?????¨??´??????????????????
bool intersect(Point p1, Point p2, Point p3, Point p4) {
	return (ccw(p1, p2, p3)*ccw(p1, p2, p4) <= 0 &&
		ccw(p3, p4, p1)*ccw(p3, p4, p2) <= 0);
}
bool intersect(Segment s1, Segment s2) { return intersect(s1.p1, s1.p2, s2.p1, s2.p2); }
//(?????????????¶????)

//2??????????????¢
double getDistance(Point a, Point b) { return (a - b).abs(); }
//??´?????¨???????????¢
double getDistanceLP(Line l, Point p) { return abs(cross(l.p2 - l.p1, p - l.p1) / (l.p2 - l.p1).abs()); }
//????????¨???????????¢
double getDistanceSP(Segment s, Point p) {
	if (dot(s.p2 - s.p1, p - s.p1) < 0.0)return (p - s.p1).abs();
	if (dot(s.p1 - s.p2, p - s.p2) < 0.0)return (p - s.p2).abs();
	return getDistanceLP(s, p);
}
//????????¨??????????????¢
double getDistance(Segment s1, Segment s2) {
	if (intersect(s1, s2))return 0.0;
	return	min(
		min(getDistanceSP(s1, s2.p1), getDistanceSP(s1, s2.p2)),
		min(getDistanceSP(s2, s1.p1), getDistanceSP(s2, s1.p2))
	);
}

//?????¨??´??????????????????
bool intersect(Circle c, Line l) { return getDistanceLP(l, c.c) <= c.r; }
//?????¨?????????????????? ??±?????\???(common tangent)?????°
int intersect(Circle c1, Circle c2) {
	double d = getDistance(c1.c, c2.c);
	if (d > c1.r + c2.r)return 4;
	if (d == c1.r + c2.r)return 3;
	if (d + c1.r == c2.r || d + c2.r == c1.r)return 1; //?????¨?????´ return ???;
	if (d + c1.r < c2.r || d + c2.r < c1.r)return 0;
	return 2;
}

//????????¨???????????????
Point getCrossPoint(Segment s1, Segment s2) {
	assert(intersect(s1, s2));
	Vector base = s2.p2 - s2.p1;
	double a1 = abs(cross(base, s1.p1 - s2.p1)); //area1
	double a2 = abs(cross(base, s1.p2 - s2.p1)); //area2
	double t = a1 / (a1 + a2);
	return s1.p1 + (s1.p2 - s1.p1)*t;
}
//??´?????¨??´????????????
//Point getCrossPointLL(Line l1, Line l2) {}

//?????¨??´????????????
pair<Point, Point> getCrossPoints(Circle c, Line l) {
	assert(intersect(c, l));
	Vector pr = project(l, c.c);
	Vector e = (l.p2 - l.p1) / (l.p2 - l.p1).abs();
	double base = sqrt(c.r*c.r - (pr - c.c).norm());
	return make_pair(pr + e*base, pr - e*base);
}
//?????¨????????????
pair<Point, Point> getCrossPoints(Circle c1, Circle c2) {
	int m = intersect(c1, c2);
	assert(m != 4 && m != 0);
	double d = (c1.c - c2.c).abs();
	double a = acos((c1.r*c1.r + d*d - c2.r*c2.r) / (2 * c1.r*d));
	double t = arg(c2.c - c1.c);
	return make_pair(c1.c + polar(c1.r, t + a), c1.c + polar(c1.r, t - a));
}

//????????????
enum { OUT = 0, ON, IN };
int contains(Polygon g, Point p) {
	int n = g.size();
	bool x = false;
	for (int i = 0; i < n; i++) {
		Point a = g[i] - p, b = g[(i + 1) % n] - p;
		if (abs(cross(a, b)) < EPS&&dot(a, b) < EPS)return ON;
		if (a.y > b.y)swap(a, b);
		if (a.y < EPS&&EPS<b.y&&cross(a, b)>EPS)x = !x;
	}
	return (x ? IN : OUT);
}

//????§???¢?????¢???
double area(Polygon g) {
	double a = 0;
	for (size_t i = 0; i < g.size(); i++)
		a += cross(g[i], g[(i + 1) % g.size()]);
	return a / 2.0;
}

//?????§????????????????¨??????????
bool isConvex(Polygon g) {
	for (size_t i = 0; i < g.size(); i++)
		if (ccw(g[i], g[(i + 1) % g.size()], g[(i + 2) % g.size()]) == CLOCKWISE)
			return false;
	return true;
}

int above[25];
signed char dp[1 << 24];//??¶??? 0?????????????????¨ 1???????????????????????????

int main() {
	for (int n; cin >> n&&n;) {
		Circle C[25];
		int c[25];
		memset(above, 0, sizeof(above));
		memset(dp, -1, sizeof(dp));

		for (int i = 0; i < n; i++) {
			cin >> C[i].c >> C[i].r >> c[i];
			for (int j = 0; j < i; j++) {
				int ct = intersect(C[i], C[j]);
				if (ct <= 2)above[i] |= (1 << j); //??????????????£????????????????¨????
			}
		}

		int ans = 0;
		int fend = (1 << n);
		dp[0] = 0;
		for (int bit = 0; bit < fend; bit++) {
			if (dp[bit] == -1)continue;
			ans = max(ans, (int)dp[bit]);
			for (int j = 0; j < n - 1; j++) {//n-1???????????§?????? (n-1,n)
				if (
					(bit&(1 << j)) == 0 //??????????????£?????????
					&& (bit&above[j]) == above[j] //??????k????????????????????????
					)
				{
					//?????¢????????£????¶??????????????????¢???
					for (int k = j + 1; k < n; k++) {
						if (
							c[j] == c[k] //????????????
							&& (bit&(1 << k)) == 0 //??????????????£?????????
							&& (bit&above[k]) == above[k] //??????k????????????????????????
							)
						{
							int h = bit | (1 << j) | (1 << k); //??????j,k????????????????????¶???
							dp[h] = dp[bit] + 2;
						}
					}
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}

Measured memory_bytes: 17628