#include<iostream>
#include<vector>
#include<cstdio>

#define f first
#define s second
#define mp make_pair

#define REP(i,n) for(int i=0; i<(int)(n); i++)

using namespace std;

int getInt(){
  int ret = 0,c;
  c = getchar();
  while(!isdigit(c)) c = getchar();
  while(isdigit(c)){
    ret *= 10;
    ret += c - '0';
    c = getchar();
  }
  return ret;
}

inline pair<int,int> hitBlow(int a, int b){
  int hit = 0;
  int blow = 0;
  int cntA[10] = { 0 };
  int cntB[10] = { 0 };

  REP(i, 4){
    int aa = a % 10;
    int bb = b % 10;

    if(aa == bb) ++hit;
    ++cntA[aa];
    ++cntB[bb];

    a /= 10;
    b /= 10;
  }

  REP(i,10){
    blow += min(cntA[i], cntB[i]);
  }
  blow -= hit;

  return mp(hit, blow);
}

inline bool different(int a){
  int cnt[10] = { 0 };
  REP(i,4){
    int aa = a % 10;
    if(cnt[aa]++ != 0)
      return false;
    a /= 10;
  }
  return true;
}

int main(){
  int n;
  while((n = getInt()) != 0){
    int fdn[n];
    int hits[n];
    int blows[n];
    vector<int> ans;

    REP(i,n){
      fdn[i] = getInt();
      hits[i] = getInt();
      blows[i] = getInt();
    }

    REP(i,10000) if(different(i)){
      REP(j,n){
        pair<int,int> ret = hitBlow(i, fdn[j]);
        int hit = ret.f;
        int blow = ret.s;

        if(hits[j] != hit || blows[j] != blow){
          goto bad;
        }
      }
      ans.push_back(i);
    bad:;
    }

    if(ans.size() == 1){
      printf("%04d\n", ans[0]);
    }else if(ans.size() > 1 && ans.size() < 25){
      bool ok = false;
      REP(i,10000) if(different(i)){
        int cnt[5][5] = {{ 0 }};
        REP(j, ans.size()){
          pair<int,int> ret = hitBlow(i, ans[j]);
          if(cnt[ret.f][ret.s]++ != 0)
            goto bad2;
        }
        printf("%04d\n", i);
        ok = true;
        break;
      bad2:;
      }
      if(!ok) puts("????");
    }else{
      puts("????");
    }
  }
  return 0;
}