#include<iostream>
#include<cmath>
#include<cstdio>
#include<string.h>
#include<cassert>
#include<vector>
#include<algorithm>
#define F first
#define S second
#define pb push_back
#define EPS 1e-10
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
using namespace std;
typedef pair<int,int> P;
typedef pair<P,P> PP;
int n,ans;
bool used[1000];
vector<PP> p;
vector<int> rank;
vector<int> List[1000];
int cross[1000];
static const int INF = 1<<28;


char dp[1<<24];
int main(){
  

  while(cin >> n && n){ 
    ans = 0;
    for(int i=0;i<n;i++)cross[i] = 0;
    p.clear(); rank.clear();
    for(int i=0;i<n;i++){
 List[i].clear();
      int x,y,r,c;
      cin >> x >> y >> r >> c;
      p.pb(PP(P(x,y),P(r,c)));
      for(int j=0;j<i;j++){
	int d1 = pow(p[i].F.F-p[j].F.F,2) + pow(p[i].F.S-p[j].F.S,2);
	int d2 = pow(p[i].S.F+p[j].S.F,2);
	if(d1 < d2){
	  cross[i] |= (1<<j);
	}
      }
    }
    // for(int i=0;i<n;i++){
    //cout << "cor - " << cross[i] << endl;
    //}
    
    memset(dp,-1,sizeof(dp));//
    dp[0] = 0;//
   
    for(int i=0;i<(1<<n);i++){//
      if(dp[i] == -1)continue;//
      ans = max(ans,(int)dp[i]);//
      for(int j=0;j<n;j++){//
	if((i&cross[j]) != cross[j] || (i&(1<<j)) != 0)continue;//
   	for(int k=j+1;k<n;k++){//
	  if(j==k || (i&cross[k])!=cross[k] || (i&(1<<k))!=0 || p[j].S.S != p[k].S.S)continue;
	  dp[i|(1<<j)|(1<<k)] = max((int)dp[i|(1<<j)|(1<<k)],(int)dp[i]+2);
	}
      }
    }
    
    // Japan - Iraq : 0 - 0 (03:14)
    // Japan - Iraq : 1 - 0 (32:02)
    // Japan - Iraq : 1 - 0 (41:00)
  










    //rec2(0); close  
 
     cout << ans << endl;
  }
  return 0;
}




























































/*

void rec(int cnt){

  int j=0,flag = 0;
  bool fl = true;
  while(fl){ 

    if(rank[j] == 0){
    
    j++;
      if(j%n == 0 && j!=0){
	j=0;
	if(finish()){
	  ans = max(ans,cnt);
	  fl = false;
	  return;
	}
	flag = 0;
      }
      continue;
    }

    if(rank[j] == 1){
      for(int i=0;i<rank.size();i++){      
	if(i == j || rank[i] <= 0)continue;
	if(rank[i] == 1 && p[j].S.S == p[i].S.S){
	  flag++;
	  rankDecrease(i);
	  rankDecrease(j);
	  rec(cnt+2);
	  rankIncrease(i);
	  rankIncrease(j);
	  flag--;
	}
      }
    }

    j++;

    if(j%n == 0 && j!=0){
      j=0;
      if(finish()){
	ans = max(ans,cnt);
	fl = false;
	return;
      }
      flag= 0;
    }
  }
}
*/













































/*

void rankIncrease(int x,int y){
 
  for(int i=0;i<List[x].size();i++){
      rank[List[x][i]]++;
    }
    rank[x]++;
    return;


  for(int i=0;i<rank.size();i++){
    if(y == i)continue;
    if(i == x){
      rank[i]++;
      continue;
    }
 double r1 = p[x].S.F,r2 = p[i].S.F,d = sqrt(pow(p[x].F.F-p[i].F.F,2)+pow(p[x].F.S-p[i].F.S,2));
 if(fabs(r1-r2) < d  && d < (r1+r2) ){ //cross each other on two different points
	rank[i]++;
      }
      else if(fabs(d-(r1+r2)) < EPS ){ //be circumscribed
      }
      else if(fabs(d-fabs(r1-r2)) < EPS){ // be inscribed
	rank[i]++;
      }
      else{
      }
  }
}

  void rankDecrease(int x,int y){
    for(int i=0;i<List[x].size();i++){
      rank[List[x][i]]--;
    }
    rank[x]--;
    return;

  for(int i=0;i<rank.size();i++){
    if(i == y)continue;
    if(i == x){
      rank[i]--;
      continue;
    }
    double r1 = p[x].S.F,r2 = p[i].S.F,d = sqrt(pow(p[x].F.F-p[i].F.F,2)+pow(p[x].F.S-p[i].F.S,2));
 if( fabs(r1-r2) < d  && d < (r1+r2)){ //cross each other on two different pointsq
	  rank[i]--;
      }
      else if( fabs(d-(r1+r2)) < EPS){ //be circumscribed
      }
      else if( fabs(d-fabs(r1-r2)) < EPS){ // be inscribed
	rank[i]--;
      }
      else{
      }
  }
}





void rec2(int cnt){
  //cout << "coumter" << endl;
   for(int i=0;i<rank.size();i++){
     if(rank[i] != 1)continue;
    //cout << ans << endl;
    if(rank[i] == 1 ){
      for(int j=0;j<rank.size();j++){
	if(i == j || rank[j] <= 0)continue;
	if(p[i].S.S == p[j].S.S && rank[j] == 1 ){//usedつかったrtsdkrkm	
	  rankDecrease(i,j); rankDecrease(j,i);
	  
	  rec2(cnt+2);
	  rankIncrease(i,j); rankIncrease(j,i);
	}
      }
    }
  }
 
  ans = max(ans,cnt);
}


*/










/*
void ranking(){
  //for(int i=0;i<p.size();i++)rank.pb(1);

  for(int i=0;i<p.size();i++){
    cross[i] = 0;
    for(int j=0;j<i;j++){
      double r1 = p[i].S.F,r2 = p[i].S.F,d = pow(p[i].F.F-p[j].F.F,2)+pow(p[i].F.S-p[j].F.S,2);
      R = pow();
      if(fabs(r1-r2) < d  && d < (r1+r2) ){ //cross each other on two different points
	//rank[j]++;
	//List[i].pb(j);
	cross[i] |= (1<<j);
      }
      else if(fabs(d-(r1+r2)) <= EPS){ //be circumscribed
      }
      else if(fabs(d-fabs(r1-r2)) <= EPS){ // be inscribed
	//rank[j]++;
	//List[i].pb(j);
	cross[i] |= (1<<j);
      }
      else{
      }
    }
    cout << "i = " << i << ",cross = " << cross[i] << endl;
  }
}
*/

Measured memory_bytes: 17620