// when run with args p1, p2, ..., pn, generates the tile set that
// simulates counting using Chinese remaindering

#include <iostream>
#include <assert.h>

using namespace std;
int *Primes;
int nPrimes;

int Glue(int x, int y) {
  y += Primes[x]; y %= Primes[x];
  int g = nPrimes+1;
  for (int i=0; i<x; ++i)
    g += Primes[i];
  g += y;
  return g;
}

int Strength(int x, int y) {
  y += Primes[x]; y%= Primes[x];
  if (y == Primes[x]-1) return 2; else return 3;
}

main(int argc, char **argv) {
  Primes = new int[argc-1];

  assert(argc > 1);
  nPrimes = argc-1;
  int nTiles = nPrimes;
  for (int i=0; i< nPrimes; ++i) {
    Primes[i] = atoi(argv[i+1]);
    nTiles += Primes[i];
    assert(Primes[i] > 1);
  }
  cout << "% The prime counting system automatically generated using" << endl
       << "% Ashish Goel's generator. The output can be run using xgrow\n";
  
  cout << "% The primes are:";
  for (int i=0; i<nPrimes; ++i)
    cout << " " << Primes[i];
  cout << endl;
  cout << "tile edges matches {{N E S W}*}" << endl;
  cout << "num tile types=" << nTiles << endl;
  cout << "num binding types="
       << nPrimes-1 // The seed row
    + 1 // The transverse glue
    + nTiles - nPrimes // Each tile has a unique north glue except the seed
       << endl;
  cout << "tile edges={" << endl;

  // Glues 1 to nPrimes -1 are reserved for the seed row and are of strength 3
  // Glue nPrimes is reserved for the transverse and is of strength 1
  // The fuunction Glue(x,y) is the glue on the north side of the y-th tile
  // for the x-th prime

  // The seed
  cout << "{" << Glue(0,0) << " 0 0 1} (red)" << endl;

  // The nPrimes-2 middle tiles in the seed row
  for (int i=1; i<nPrimes-1; ++i)
    cout << "{" << Glue(i,0) << " " << i << " 0 " << i+1 << "} (red)" << endl;
  
  // The final tile in the seed row
  cout << "{" << Glue(nPrimes-1,0) << " " << nPrimes-1 << " 0 0} (red)" << endl;
  
  for (int i=0; i<nPrimes; ++i)
    for (int j=0; j<Primes[i]; ++j) {
      cout << "{" << Glue(i,j) << " " << nPrimes << " " 
	   << Glue(i,j-1) << " " << nPrimes << "}";
      if (j == 0)
	cout << " (red)" << endl;
      else
	cout << " (blue)" << endl;
    }

  cout << "}" << endl;

  cout << "binding strengths={";
  
  // First, the seed glues
  for (int i=0; i<nPrimes-1; ++i)
    cout << "3 ";

  // Now, the transverse glue
  cout << "1";
  
  // Now, the tile glues
  for (int i=0; i<nPrimes; ++i)
    for (int j=0; j<Primes[i]; ++j)
      cout << " " << Strength(i,j);
  
  cout << "}" << endl;
}


