#include <iostream>
#include <assert.h>
#include <set>
#include <stdlib.h>
#include <vector>

using namespace std;

int complete_single(int a, int b) {
  assert(a >=0 && a < 3);
  assert(b >=0 && b < 3);
  if (a == b) return a;
  return (3-a-b);
}

int complete_set(int a, int b) {
  assert(a >=0 && a < 81);
  assert(b >=0 && b < 81);
  if (a<3 && b<3) return complete_single(a,b);
  return (complete_set(a/3,b/3) * 3 + complete_single(a%3,b%3));
}

bool is_set(int a, int b, int c) {
  return (c == complete_set(a,b));
}

set<set<int> > sets;
set<set<int> > supersets;
set<set<int> > hypersets;

void gensets() {
  for (int a=0;a<81;a++) for (int b=a+1;b<81;b++) {
    int c = complete_set(a,b);
    if (c>a && c>b) {
      set<int> foo;
      foo.insert(a);
      foo.insert(b);
      foo.insert(c);
      sets.insert(foo);
      //cout << "set " << a << " " << b << " " << c << "\n";
    }
  }
}

set<int> complete_superset(int a, int b, int c) {
  assert(!is_set(a,b,c));
  set<int> answer;
  answer.insert(complete_set(c,complete_set(a,b)));
  answer.insert(complete_set(a,complete_set(c,b)));
  answer.insert(complete_set(b,complete_set(a,c)));
  return answer;
}

void gensupersets() {
  for (int a=0;a<81;a++) 
  for (int b=a+1;b<81;b++) 
  for (int c=b+1;c<81;c++) {
    if (is_set(a,b,c)) continue;
    set<int> stuff = complete_superset(a,b,c);
    for (set<int>::iterator it = stuff.begin(); it != stuff.end(); ++it) {
      if (*it <= c) continue;
      set<int> foo;
      foo.insert(a);
      foo.insert(b);
      foo.insert(c);
      foo.insert(*it);
      supersets.insert(foo);
      //cout << "superset " << a << " " << b << " " << c << " " << *it << "\n";
    }
  }
}

bool is_superset(set<int>& ss) {
  return (supersets.find(ss) != supersets.end());
}

int complete_hyperset(set<int>& ss) {
  assert(!is_superset(ss));
  vector<int> stuff;
  for (set<int>::iterator it = ss.begin(); it != ss.end(); ++it) {
    stuff.push_back(*it);
  }
  int h1 = complete_set(stuff[0],stuff[1]); 
  int h2 = complete_set(stuff[0],stuff[2]); 
  int h3 = complete_set(stuff[0],stuff[3]); 
  int h4 = complete_set(stuff[1],stuff[2]); 
  int h5 = complete_set(stuff[1],stuff[3]); 
  int h6 = complete_set(stuff[2],stuff[3]); 
  int piv = complete_set(h1,h6);
  assert(is_set(piv,h2,h5));
  assert(is_set(piv,h3,h4));
  return piv; 
}

void genhypersets() {
  for (int a=0;a<81;a++) 
  for (int b=a+1;b<81;b++) 
  for (int c=b+1;c<81;c++) 
  for (int d=c+1;d<81;d++) {
    if (is_set(a,b,c)) continue;
    if (is_set(a,b,d)) continue;
    if (is_set(a,c,d)) continue;
    if (is_set(b,c,d)) continue;
    set<int> stuff;
    stuff.insert(a);
    stuff.insert(b);
    stuff.insert(c);
    stuff.insert(d);
    if (is_superset(stuff)) continue;
    stuff.insert(complete_hyperset(stuff));
    //cout << "hyperset";
    for (set<int>::iterator it = stuff.begin(); it != stuff.end(); ++it) {
      //cout << " " << *it;
    }
    //cout << "\n";
    hypersets.insert(stuff);
  }
}

int randcard() {
  return (int)(81*((double)rand() / ((double)(RAND_MAX) + (double)(1))));
}

set<int> gendeal(int count) {
  set<int> answer;
  while (answer.size() < count) {
    int val = randcard();
    answer.insert(val);
    //cout << " " << val;
  }
  return answer;
}

int count_set(set<int>& ss) {
  int answer = 0;
  vector<int> stuff;
  for (set<int>::iterator it = ss.begin(); it != ss.end(); ++it) {
    stuff.push_back(*it);
  }
  int size = ss.size();
  for (int a=0;a<size;a++) 
  for (int b=a+1;b<size;b++) 
  for (int c=b+1;c<size;c++) {
    if (is_set(stuff[a],stuff[b],stuff[c])) answer++;
  }
  return answer;
}

int count_superset(set<int> ss) {
  int answer = 0;
  vector<int> stuff;
  for (set<int>::iterator it = ss.begin(); it != ss.end(); ++it) {
    stuff.push_back(*it);
  }
  int size = ss.size();
  for (int a=0;a<size;a++) 
  for (int b=a+1;b<size;b++) 
  for (int c=b+1;c<size;c++) 
  for (int d=c+1;d<size;d++) {
    set<int> temp;
    temp.insert(stuff[a]);
    temp.insert(stuff[b]);
    temp.insert(stuff[c]);
    temp.insert(stuff[d]);
    if (is_superset(temp)) answer++;
  }
  return answer;
}

int count_hyperset(set<int> ss) {
  int answer = 0;
  vector<int> stuff;
  for (set<int>::iterator it = ss.begin(); it != ss.end(); ++it) {
    stuff.push_back(*it);
  }
  int size = ss.size();
  for (int a=0;a<size;a++) 
  for (int b=a+1;b<size;b++) 
  for (int c=b+1;c<size;c++) 
  for (int d=c+1;d<size;d++)
  for (int e=d+1;e<size;e++) {
    set<int> temp;
    temp.insert(stuff[a]);
    temp.insert(stuff[b]);
    temp.insert(stuff[c]);
    temp.insert(stuff[d]);
    temp.insert(stuff[e]);
    if (hypersets.find(temp) != hypersets.end()) answer++;
  }
  return answer;
}

int print_set(set<int>& ss) {
  int answer = 0;
  vector<int> stuff;
  for (set<int>::iterator it = ss.begin(); it != ss.end(); ++it) {
    stuff.push_back(*it);
  }
  int size = ss.size();
  for (int a=0;a<size;a++) 
  for (int b=a+1;b<size;b++) 
  for (int c=b+1;c<size;c++) {
    if (is_set(stuff[a],stuff[b],stuff[c])) {
      cout << stuff[a] << " "
           << stuff[b] << " "
           << stuff[c] ;
      answer++;
    }
  }
  return answer;
}

int print_superset(set<int> ss) {
  int answer = 0;
  vector<int> stuff;
  for (set<int>::iterator it = ss.begin(); it != ss.end(); ++it) {
    stuff.push_back(*it);
  }
  int size = ss.size();
  for (int a=0;a<size;a++) 
  for (int b=a+1;b<size;b++) 
  for (int c=b+1;c<size;c++) 
  for (int d=c+1;d<size;d++) {
    set<int> temp;
    temp.insert(stuff[a]);
    temp.insert(stuff[b]);
    temp.insert(stuff[c]);
    temp.insert(stuff[d]);
    if (is_superset(temp)) {
      cout << stuff[a] << " "
           << stuff[b] << " "
           << stuff[c] << " "
           << stuff[d] ;
      answer++;
    }
  }
  return answer;
}

int print_hyperset(set<int> ss) {
  int answer = 0;
  vector<int> stuff;
  for (set<int>::iterator it = ss.begin(); it != ss.end(); ++it) {
    stuff.push_back(*it);
  }
  int size = ss.size();
  for (int a=0;a<size;a++) 
  for (int b=a+1;b<size;b++) 
  for (int c=b+1;c<size;c++) 
  for (int d=c+1;d<size;d++)
  for (int e=d+1;e<size;e++) {
    set<int> temp;
    temp.insert(stuff[a]);
    temp.insert(stuff[b]);
    temp.insert(stuff[c]);
    temp.insert(stuff[d]);
    temp.insert(stuff[e]);
    if (hypersets.find(temp) != hypersets.end()) {
      cout << stuff[a] << " "
           << stuff[b] << " "
           << stuff[c] << " "
           << stuff[d] << " "
           << stuff[e] ;
      answer++;
    }
  }
  return answer;
}

void print(set<int> ss) {
  for (set<int>::iterator it = ss.begin(); it != ss.end(); ++it) {
    cout << " " << *it;
  }
}

int main() {
  gensets();
  gensupersets();
  genhypersets();
  cout << "Generation done.\n";
  long long trials=0; long long has=0;
  while (1) {
    trials++;
    set<int> deal = gendeal(10);
    cout << count_set(deal) << " ";
    cout << count_superset(deal) << " ";
    cout << count_hyperset(deal) << " ";
    print(deal);
    cout << "{ "; print_set(deal); cout << " } ";
    cout << "{ "; print_superset(deal); cout << " } ";
    cout << "{ "; print_hyperset(deal); cout << " } ";
    cout << "\n";
  }
}
