#include "onedraft.h"

int expands[10][2][4] = {
 {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
 {{ 9, 0, 1, 1}, { 1, 1, 9, 0}},
 {{ 9, 2, 2, 0}, { 9, 2, 2, 0}},
 {{ 0, 0, 0, 0}, { 0, 0, 0, 0}},
 {{ 4, 9, 4, 0}, { 9, 4, 0, 4}},
 {{ 5, 0, 5, 9}, { 0, 5, 9, 5}},
 {{ 9, 9, 9, 9}, { 9, 9, 9, 9}},
 {{ 0, 7, 7, 9}, { 0, 7, 7, 9}},
 {{ 0, 9, 8, 8}, { 8, 8, 0, 9}},
 {{ 9, 9, 9, 9}, { 9, 9, 9, 9}}};

void onedraft::clear ( void ) {
  for (int lcv1=0;lcv1<MAX;lcv1++)
  for (int lcv2=0;lcv2<MAX;lcv2++) {
    data[lcv1][lcv2]=0;
  }
}

onedraft::onedraft ( ) {
  this->clear();
}

onedraft::onedraft ( const onedraft & x ) {
  for (int lcv1=0;lcv1<MAX;lcv1++)
  for (int lcv2=0;lcv2<MAX;lcv2++) {
    this->data[lcv1][lcv2]=x.data[lcv1][lcv2];
  }
}

onedraft::~onedraft ( ) {
  // nothing to free up
}

onedraft & onedraft::operator = ( const onedraft & x ) {
  for (int lcv1=0;lcv1<MAX;lcv1++)
  for (int lcv2=0;lcv2<MAX;lcv2++) {
    this->data[lcv1][lcv2]=x.data[lcv1][lcv2];
  }
  return *this;
}

void onedraft::dub (void) {
  int toprow;
  int smallmax = MAX/2-1;
  int box[2];
  onedraft old;

  old = *this;

    this->clear();
    for (int lcv1=smallmax;lcv1>=0;lcv1--)
    for (int lcv2=smallmax;lcv2>=0;lcv2--) {
      int org=old.data[lcv1][lcv2];
      box[0] = org%64/7; 
      box[1] = org/64/7; 
      for (int lcv3=1;lcv3<100;lcv3+=63) {
        int off = lcv3==64? 1 : 0;
        this->data[lcv1*2][lcv2*2] += lcv3*7*expands[box[off]][off][0];
        this->data[lcv1*2+1-off][lcv2*2+off] = 
          7*expands[box[off]][off][1] + 64*7*expands[box[off]][off][2];
        this->data[lcv1*2+1][lcv2*2+1] += lcv3*7*expands[box[off]][off][3];
      }
    }
}

onedraft & onedraft::operator << ( int amt ) {
  int toprow;
  onedraft old;

  old = *this;
  assert(amt>=0);
  assert(amt<6);

  for (int turns=0;turns<amt;turns++) {
    // first, find the top row
    toprow=0;
    for (int lcv1=0;lcv1<MAX;lcv1++)
    for (int lcv2=0;lcv2<MAX;lcv2++) {
      if (old.data[lcv1][lcv2]!=0
        && toprow < lcv2-lcv1+(old.data[lcv1][lcv2]>63?1:0)) 
           toprow = lcv2-lcv1+(old.data[lcv1][lcv2]>63?1:0);
    }
    this->clear();
    for (int lcv1=0;lcv1<MAX;lcv1++)
    for (int lcv2=0;lcv2<MAX;lcv2++) 
    for (int lcv3=0;lcv3<2;lcv3++) {
      int dst; int dold[2];
      dold[0] = old.data[lcv1][lcv2]%64/7;
      dold[1] = old.data[lcv1][lcv2]/64/7;
      switch (dold[lcv3]) {
        case 0: dst = 0 ; break;
        case 1: dst = 2 ; break;
        case 2: dst = 4 ; break;
        case 4: dst = 8 ; break;
        case 5: dst = 1 ; break;
        case 7: dst = 5 ; break;
        case 8: dst = 7 ; break;
        case 9: dst = 9 ; break;
      }
      this->data[toprow-lcv2+lcv1-lcv3][lcv1] += dst*7*(lcv3==0?64:1);
    }
  }
  return *this;
}

onedraft & onedraft::operator >> ( int amt ) {
  assert(amt>=0);
  assert(amt<6);
  if (amt != 0) (*this << (6-amt));
  return *this;
}

onedraft & onedraft::operator ! (void) {
  onedraft old;

  old = *this;

  this->clear();
  for (int lcv1=0;lcv1<MAX;lcv1++)
  for (int lcv2=0;lcv2<MAX;lcv2++) 
  for (int lcv3=0;lcv3<2;lcv3++) {
    int dst; int dold[2];
    dold[0] = old.data[lcv1][lcv2]%64/7;
    dold[1] = old.data[lcv1][lcv2]/64/7;
    switch (dold[lcv3]) {
      case 0: dst = 0 ; break;
      case 1: dst = 4 ; break;
      case 2: dst = 2 ; break;
      case 4: dst = 1 ; break;
      case 5: dst = 8 ; break;
      case 7: dst = 7 ; break;
      case 8: dst = 5 ; break;
      case 9: dst = 9 ; break;
    }
    this->data[lcv2][lcv1] += dst*7*(lcv3==0?64:1);
  }
  return *this;
}

istream & operator >> ( istream & in ,       onedraft & x) {
  int temp,temp2;
  int insanityx = 0;
  int insanityq = 0;
  int row=0;int col=0;

  x.clear();
  in >> ws;
  while (in.peek() != 'Q') {
    insanityq++;
    in >> ws;
    while (in.peek() != 'X') {
      insanityx++;
      in >> temp >> temp2;
      x.data[row][col] = (temp+64*temp2)*7;
      col++;
      in >> ws;
      assert(insanityx<65000);
    }
    insanityx=0;
    in.get();
    in >> ws;
    row++;
    col=0;
    assert(insanityq<65000);
  }
  in.get();
}

ostream & operator << ( ostream & out, const onedraft & x) {
  int maxrow=0; int maxcol=0;
  for (int lcv=0;lcv<MAX;lcv++) for (int lcv2=0;lcv2<MAX;lcv2++)  
    if (x.data[lcv][lcv2] != 0) maxrow=lcv+1;
  for (int lcv=0;lcv<maxrow;lcv++) { 
    for (int lcv2=0;lcv2<MAX;lcv2++)  
      if (x.data[lcv][lcv2] != 0) maxcol=lcv2+1;
    for (int lcv2=0;lcv2<maxcol;lcv2++) { 
      out << x.data[lcv][lcv2]%64/7 << " "
          << x.data[lcv][lcv2]/64/7 << " ";
    }
    out << "X\n";
  }
  out << "Q\n";
}

