#include <iostream>
#include <math.h>
#include <assert.h>
#include <algorithm>
#include <sstream>
#include <stdio.h>
#include <vector>
#include <set>
#include <iterator>

using namespace std;

const int size = 10;

int stack = 0;

class Cell;
class Light;
class GridLight;

void sanityCheck();

class CellIterator : public iterator<forward_iterator_tag, int> {
 public:
  void reset();
  CellIterator(Cell* cell) {
    mycell = cell;
    reset();
  }
  CellIterator(Cell& cell) {
    mycell = &cell;
    reset();
  }
  int operator*() const {
    if (myvalue == 10) return -1;
    return myvalue;
  }
  CellIterator& operator++();
  Cell * mycell;
  int myvalue;
};

class GridLightIterator : public iterator<forward_iterator_tag, int> {
 public:
  GridLightIterator(GridLight& light);
  void CheckCarry(int i) {
    if (i == 0) return;
    if (*its[i] == -1) {
      ++its[i-1];
      its[i].reset();
      CheckCarry(i-1);
    }
  }
  long long Value() const {
    long long answer = 0;
    for (int i=0;i<its.size();++i) {
      answer *= 10;
      answer += *its[i];
    }
    return answer;
  }
  long long operator*() const {
    if (*its[0] == -1) return -1;
    return Value();
  }
  GridLightIterator& operator++() {
    if (*its[0] == -1) return *this;
    ++its[its.size()-1];
    CheckCarry(its.size()-1);
    return *this;
  }
  GridLight * mylight;
  vector<CellIterator> its;
};

class Cell {
 public:
  Cell() : black(true) {
    for (int i=0;i<10;i++)
      possble_[i] = true;
  }
  bool black;
  Cell* up;
  Cell* down;
  Cell* left;
  Cell* right;
  int index;
  vector<Light*> lights;
  int count() const {
    int x = 0;
    for (int i=0;i<10;i++)
      if (possble_[i]) x++;
    return x;
  }
  char value() const {
    int c = count();
    if (c == 10) return 'X';
    return (char)((short)c+(short)'0');
  }
  char certain() const {
    int c = count();
    if (c != 1) return '?';
    int p = 0;
    while (!possible(p)) p++;
    return (char)((short)p+(short)'0');
  }
  bool possible(int i) const {
    return possble_[i];
  }
  void uniquify(int val) {
    assert(possble_[val]);
    for (int i=0;i<10;i++) {
      if (i!=val)
        setPossible(i, false);
    }
  }
  void setPossible(int i, bool value) {
    assert(i >= 0);
    assert(i < 10);
    if (possble_[i] != value) {
      cout << " setting " << index << "C to not be " << i << "\n";
      possble_[i] = value;
      Refresh();
    }
  }
  void Refresh();
  int min() const {
    int answer = 0;
    while (!(possble_[answer])) answer++;
    assert(answer < 10);
    return answer;
  }
  int max() const {
    int answer = 9;
    while (!(possble_[answer])) answer--;
    assert(answer >= 0);
    return answer;
  }
 private:
  bool possble_[10];
};

int ten(int pow) {
  if (pow == 0) return 1;
  return 10*ten(pow-1);
}

class Light;

class Constraint {
 public:
  Constraint() { name_ = ""; }
  virtual void Refresh() {}
  string name() const {
    return name_;
  }
  void append(string s) {
    name_ += s;
  }
  void append(int s) {
    char foo[50];
    sprintf(foo, "%d", s);
    name_ += foo;
  }
 private:
  string name_;
};

class Light {
 public:
  Light(string nm) {
    min = 0;
    max = 99999999999LL;
    name_ = nm;
  }
  Light(string nm, long long mn, long long mx) {
    min = mn;
    max = mx;
    name_ = nm;
  }
  Light(string nm, long long val) {
    min = val;
    max = val;
    name_ = nm;
  }
  vector<Constraint*> constraints;
  long long min, max;
  set<long long> values;
  virtual string name() const {
    return name_;
  }
  bool exact() const {
    return (!values.empty());
  }
  void printValues() const {
    if (exact()) {
      for (set<long long>::iterator it = values.begin();
           it != values.end(); ++it) {
        cout << (*it) << " ";
      }
    }
  }
  bool hasVal(long long val) {
    if (exact()) {
      return (values.find(val) != values.end());
    } else {
      if (val < min) return false;
      if (val > max) return false;
      return true;
    }
  }
  void printSummary() const {
    cout << "   " << name() << " : ";
    if (values.size() == 0) {
      cout << min << " ... " << max;  
      cout << "(many values)";
    } else if (values.size() < 101) {
      printValues();
      cout << "(" << values.size() << " values)";
    } else if (values.size() >= 101) {
      int count = 0;
      bool ellipse = false;
      for (set<long long>::iterator it = values.begin();
           it != values.end(); ++it) {
        if (count < 20 || (values.size() - count) < 20) {
          cout << (*it) << " ";
        }
        if (count > 20 && !(ellipse)) {
          cout << "... ";
          ellipse = true;
        }
        count++;
      }
      cout << "(" << values.size() << " values)";
    }
    cout << "\n";
  }
  virtual void Refresh() {
    sanityCheck();
cout << "Updating " << name();
    bool changed = false;
    if (!exact() && (max - min < 1000)) {
cout << " converting to exact " << (max-min+1);
      changed = true;
      for (int i=min;i<=max;++i)
        values.insert(i);
    }
    if (exact()) {
      long long vmin = *(values.begin());
      long long vmax = *(values.rbegin());
      if (vmin < min) {
        vector<long long> deleteme;
        for (set<long long>::iterator it=values.begin();it!=values.end();++it)
          if (*it < min) deleteme.push_back(*it);
        for (int i=0;i<deleteme.size();++i)
          values.erase(deleteme[i]);
        changed = true;
cout << " removing values below " << min;
      }
      if (vmin > min) { 
        min = vmin; changed = true; 
cout << " raising min to " << min;
      }
      if (vmax > max) {
        vector<long long> deleteme;
        for (set<long long>::iterator it=values.begin();it!=values.end();++it)
          if (*it > max) deleteme.push_back(*it);
        for (int i=0;i<deleteme.size();++i)
          values.erase(deleteme[i]);
        changed = true;
cout << " removing values above " << max;
      }
      if (vmax < max) { 
        max = vmax; changed = true; 
cout << " lowering max to " << max;
      }
    }
    if (changed) {
cout << "(inspecting constraints...)\n";
cout << stack << " Pushing from " << name() << endl;
stack++;
      for (int i=0;i<constraints.size();++i) {
        constraints[i]->Refresh();
      }
stack--;
cout << stack << " Popping back to " << name() << endl;
    } else {
cout << " no change \n";
    }
    if (min == max) {
      cout << name() << " is solved! " << min << endl;
      if (values.size() != 1) {
        values.clear();
        values.insert(min);
        for (int i=0;i<constraints.size();++i) {
          constraints[i]->Refresh();
        }
      }
    }
  }
  long long rangesize() const {
    if (exact()) return values.size();
    return (max - min + 1);
  }
  virtual void printRange() const {
    printSummary();
/*
    cout << name() << " : ";
    if (min == max) {
      cout << min << " (unique)\n";
      return;
    }
    cout << min << ".." << max;
    cout << " ( " << rangesize() << " values ";
    if (exact()) cout << "exactly ";
    cout << ")";
    cout << "\n";
*/
  }

 private:
  string name_;
};

class GridLight : Light{
 public:
  GridLight(int ind, bool is_across, Cell* start) 
    : Light(""),
      index(ind),
      across(is_across) {
    contents.empty();
    Cell* cur = start;
    while (!cur->black) {
      contents.push_back(cur);
      cur->lights.push_back(this);
      cur = across ? cur->right : cur->down;
    }
    min = ten(length()-1);
    max = ten(length())-1;
    values.clear();
  }
  GridLight(int ind, bool is_across, Cell* start, int count) 
    : Light(""),
      index(ind),
      across(is_across) {
    contents.empty();
    Cell* cur = start;
    for (int i=0;i<count;i++) {
      contents.push_back(cur);
      cur->lights.push_back(this);
      cur = across ? cur->right : cur->down;
    }
    min = ten(length()-1);
    max = ten(length())-1;
    values.clear();
  }
  vector<Cell*> contents;
  bool across;
  int index;
  string name() const {
    string answer;
    stringstream foo(answer, stringstream::out | stringstream::in );
    foo << index << (across ? 'A' : 'D');
    foo >> answer;
    return answer;
  }
  void printRange() const {
    Light::printRange();
  }
  long long cellrange() const {
    long long answer = 1;
    for (int i=0;i<contents.size();++i) {
      answer *= contents[i]->count();
    }
    return answer;
  }
  void Refresh() {
    Light::Refresh();
cout << "Updating " << name();
    bool changed = false;
    long long heomin = theomin();
    long long heomax = theomax();
    if (heomin > min) {
cout << " raising min to " << heomin;
      min = heomin;
      changed = true;
    }
    if (heomax < max) {
cout << " lowering max to " << heomax;
      max = heomax;
      changed = true;
    }
    if (!exact() && (cellrange() < 1000)) {
      GridLightIterator gli(*this);
      while (*gli != -1) {
        values.insert(*gli);
        ++gli;
      }
      changed = true;
    } else if (!exact()) {
      int tempmin = min;
      int tempmax = max;
      int shear = length()-1;
      while (tempmin != tempmax) {
        shear--;
        tempmin /= 10;
        tempmax /= 10;
      }
      while (shear >= 0) {
        if (contents[shear]->count() != 1) {
          changed = true;
          contents[shear]->uniquify(tempmin % 10);
cout << " uniqufying " << shear << " to " << (tempmin % 10);
        }
        shear--;
        tempmin /= 10;
      }
    } else {
//    cout << "  looking at all values ";
//printValues();
//cout << endl;
      set<long long> deleteme;
      for (set<long long>::iterator it=values.begin();it!=values.end();++it) {
        int num = *it;
//cout << contents.size() << "\n";
        for (int i=0;i<contents.size();++i) {
          if (!(contents[contents.size()-1-i]->possible(num%10))) {
//cout << num << " FAILED\n";
            deleteme.insert(*it);
          } else {
//cout << num << " OK\n";
          }
          num /= 10;
        }
      }
      for (set<long long>::iterator it=deleteme.begin();
              it!=deleteme.end();++it) {
        values.erase(*it);
      }
      assert(!values.empty());
      bool seen[10*length()];
      for (int i=0;i<10*length();++i) seen[i] = false;
      for (set<long long>::iterator it=values.begin();it!=values.end();++it) {
        int num = *it;
        if (num >= min && num <= max) {
          for (int pos=0;pos<length();++pos) {
            seen[pos*10+(num%10)] = true;
            num /= 10;
          }
        }
      }
      for (int pos=0;pos<length();++pos) {
        int dpos = (length() - pos - 1);
        for (int dig=0;dig<10;++dig) {
          if (!seen[pos*10+dig]) {
            if (contents[dpos]->possible(dig)) {
              changed = true;
stack++;
              contents[dpos]->setPossible(dig,false);
stack--;
            }
          }
        }
      }
    }
    if (changed) {
cout << " updating constraints\n";
cout << stack << " Pushing from " << name() << endl;
stack++;
      for (int i=0;i<constraints.size();++i) {
        constraints[i]->Refresh();
      }
stack--;
cout << stack << " Popping back to " << name() << "\n";
    } else {
cout << " no change \n";
    }
    if (min == max) {
      cout << name() << " is solved! Woo. " << min << endl;
      while (values.size() != 1 || cellrange() != 1) {
        values.clear();
        values.insert(min);
        int shear = contents.size() - 1;
        long long tempmin = min;
        while (shear >= 0) {
          contents[shear]->uniquify(tempmin % 10);
cout << " uniqufying " << shear << " to " << (tempmin % 10);
          shear--;
          tempmin /= 10;
        }
        for (int i=0;i<constraints.size();++i) {
          constraints[i]->Refresh();
        }
      }
    }
  }
  int length() const {
    return contents.size();
  }
  void printCells() const {
    cout << name() << " : ";
    for (int i=0; i<contents.size(); ++i) {
      cout << contents[i]->index << " ";
    }
    cout << "\n";
  }
  long long theomin() const {
    long long answer = 0;
    for (int i=0; i<contents.size(); ++i) {
      answer *= 10;
      answer += contents[i]->min();
    }
    return answer;
  }
  long long theomax() const {
    long long answer = 0;
    for (int i=0; i<contents.size(); ++i) {
      answer *= 10;
      answer += contents[i]->max();
    }
    return answer;
  }
};

GridLightIterator::GridLightIterator(GridLight& light) {
  mylight = &light;
  for (int i=0;i<mylight->contents.size();++i) {
    its.push_back(CellIterator(mylight->contents[i]));
  }
}

void Cell::Refresh() {
  for (int i=0;i<lights.size();i++) {
    lights[i]->Refresh();
  }
}

Cell grid[size*size];
Cell nowhere;
vector<GridLight*> across;
vector<GridLight*> down;
vector<Light*> others;

Light* findLight(string s) {
  for (int i=0; i<others.size(); ++i) {
    if (others[i]->name() == s) return others[i];
  }
  for (int i=0; i<across.size(); ++i) {
    if (across[i]->name() == s) return (Light*)across[i];
  }
  for (int i=0; i<down.size(); ++i) {
    if (down[i]->name() == s) return (Light*)down[i];
  }
  cout << s << endl;
  assert(false);
  return(NULL);
}

class ConMultiple : Constraint {
 public:
  ConMultiple(string base, string multiple, int times) {
    base_ = findLight(base);
    multiple_ = findLight(multiple);
    base_->constraints.push_back(this);
    multiple_->constraints.push_back(this);
    times_ = times;

    append(base_->name());
    append(" * ");
    append(times_);
    append(" = ");
    append(multiple_->name());
  }
  void Refresh() {
    cout << "Inspecting " << name() << endl;
    base_->printSummary();
    multiple_->printSummary();
    bool base_change = false;
    bool multiple_change = false;
    if (!base_->exact() && !multiple_->exact()) {
      cout << "  looking at ranges" << endl;
      if (base_->min * times_ < multiple_->min) {
        base_->min = multiple_->min / times_;
        while (base_->min * times_ < multiple_->min) {
          base_->min++;
        }
        base_change = true;
      }
      if (base_->min * times_ > multiple_->min) {
        multiple_->min = base_->min * times_;
        multiple_change = true;
      }

      if (base_->max * times_ > multiple_->max) {
        base_->max = multiple_->max / times_;
        base_change = true;
      }
      if (base_->max * times_ < multiple_->max) {
        multiple_->max = base_->max * times_;
        multiple_change = true;
      }

    } else if (!base_->exact() && multiple_->exact()) {
      cout << "  deriving " << base_->name() << endl;
      vector<long long> deleteme;
      for (set<long long>::iterator it=multiple_->values.begin();
           it != multiple_->values.end(); ++it) {
        if (*it % times_ != 0) {
          deleteme.push_back(*it);
        } else {
          base_->values.insert(*it / times_);
        }
      }
      base_change = true;
      for (int i=0;i<deleteme.size(); i++) {
        multiple_change = true;
        multiple_->values.erase(deleteme[i]);
      }

    } else if (base_->exact() && !multiple_->exact()) {
      cout << "  deriving " << multiple_->name() << endl;
      for (set<long long>::iterator it=base_->values.begin();
           it != base_->values.end(); ++it) {
        multiple_->values.insert(*it * times_);
      }
      multiple_change = true;

    } else if (base_->exact() && multiple_->exact()) {
      cout << "  fixing intersections" << endl;
      vector<long long> deleteme;
      for (set<long long>::iterator it=multiple_->values.begin();
           it != multiple_->values.end(); ++it) {
        if (*it % times_ != 0) {
          deleteme.push_back(*it);
        } else if ((base_->values.find(*it / times_)) == base_->values.end()) {
          deleteme.push_back(*it);
        }
      }
      for (int i=0;i<deleteme.size(); i++) {
        multiple_change = true;
        multiple_->values.erase(deleteme[i]);
      }

      deleteme.clear();

      for (set<long long>::iterator it=base_->values.begin();
           it != base_->values.end(); ++it) {
        if ((multiple_->values.find(*it * times_))
             == multiple_->values.end()) {
          deleteme.push_back(*it);
        }
      }
      for (int i=0;i<deleteme.size(); i++) {
        base_change = true;
        base_->values.erase(deleteme[i]);
      }
    }
    cout << stack << " Multiple Push\n"; stack++;
    if (base_change) base_->Refresh();
    if (multiple_change) multiple_->Refresh();
    stack--; cout << stack << " Multiple Pop\n";
  }
 private:
  Light* base_;
  Light* multiple_;
  int times_;
};

long long reverse(long long val) {
  if (val % 10 == 0) return -1;
  long long answer = 0;
  while (val > 0) {
    answer *= 10;
    answer += val % 10;
    val /= 10;
  }
  return answer;
}

class ConReverse : Constraint {
 public:
  ConReverse(string base, string rev) {
    base_ = findLight(base);
    rev_ = findLight(rev);
    base_->constraints.push_back(this);
    rev_->constraints.push_back(this);

    append(base_->name());
    append(" reverseof ");
    append(rev_->name());
  }
  void Refresh() {
    cout << "Inspecting " << name() << endl;
    bool base_change = false;
    bool rev_change = false;
    if (!base_->exact() && !rev_->exact()) {
    } else if (!base_->exact() && rev_->exact()) {
      cout << "  deriving " << base_->name() << endl;
      vector<long long> deleteme;
      for (set<long long>::iterator it=rev_->values.begin();
           it != rev_->values.end(); ++it) {
        long long rv = reverse(*it);
        if (rv == -1) {
          deleteme.push_back(*it);
        } else {
          base_->values.insert(rv);
        }
      }
      base_change = true;
      for (int i=0;i<deleteme.size(); i++) {
        rev_change = true;
        rev_->values.erase(deleteme[i]);
      }

    } else if (base_->exact() && !rev_->exact()) {
      cout << "  deriving " << rev_->name() << endl;
      vector<long long> deleteme;
      for (set<long long>::iterator it=base_->values.begin();
           it != base_->values.end(); ++it) {
        long long rv = reverse(*it);
        if (rv == -1) {
          deleteme.push_back(*it);
        } else {
          rev_->values.insert(rv);
        }
      }
      rev_change = true;
      for (int i=0;i<deleteme.size(); i++) {
        base_change = true;
        base_->values.erase(deleteme[i]);
      }

    } else if (base_->exact() && rev_->exact()) {
      set<long long> revs;
      vector<long long> deleteme;
      for (set<long long>::iterator it=base_->values.begin();
           it != base_->values.end(); ++it) {
        long long rv = reverse(*it);
        if ((rv == -1) 
            || (rev_->values.find(rv) == rev_->values.end())) {
          deleteme.push_back(*it);
        } else {
          revs.insert(rv);
        }
      }

      for (int i=0;i<deleteme.size(); i++) {
        base_change = true;
        base_->values.erase(deleteme[i]);
      }

      set<long long> diff;

      set_difference(rev_->values.begin(), rev_->values.end(),
                     revs.begin(), revs.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        rev_->values.erase(*it);
        rev_change = true;
      }
      diff.clear();
    }
    cout << stack << " Reverse Push\n"; stack++;
    if (base_change) base_->Refresh();
    if (rev_change) rev_->Refresh();
    stack--; cout << stack << " Reverse Pop\n";
  }
 private:
  Light* base_;
  Light* rev_;
  int times_;
};

class ConDigsum : Constraint {
 public:
  ConDigsum(string base, string digsum) {
    base_ = findLight(base);
    digsum_ = findLight(digsum);
    base_->constraints.push_back(this);
    digsum_->constraints.push_back(this);

    append(base_->name());
    append(" has digit sum ");
    append(digsum_->name());
  }

  long long digsum(long long x) {
    int answer = 0;
    while (x > 0) {
      answer += x % 10;
      x /= 10;
    }
    return answer;
  }
  
  void Refresh() {
    cout << "Inspecting " << name() << endl;
    bool base_change = false;
    bool digsum_change = false;
    if (!base_->exact() && !digsum_->exact()) {
      long long a, b;
      a = digsum_->min / 9;
      b = digsum_->min % 9;
      while (a > 0) {
        b *= 10;
        b += 9;
        a--;
      }
      if (base_->min < b) {
        base_->min = b;
        base_change = true;
      }
      a = 1; b = 0;
      while (a <= base_->max+1) {
        a *= 10; b++;
      }
      a /= 10; b--;
      b = (base_->max+1) / a + b * 9 - 1;
      if (digsum_->max > b) {
        digsum_->max = b;
        digsum_change = true;
      }

    } else if (!base_->exact() && digsum_->exact()) {

    } else if (base_->exact() && !digsum_->exact()) {
      for (set<long long>::iterator it=base_->values.begin();
           it != base_->values.end(); ++it) {
        digsum_->values.insert(digsum(*it));
        digsum_change = true;
      }

    } else if (base_->exact() && digsum_->exact()) {
      set<long long> bases;
      set<long long> digsums;
      for (set<long long>::iterator it1=base_->values.begin();
           it1 != base_->values.end(); ++it1) {
        if (digsum_->values.find(digsum(*it1)) != 
            digsum_->values.end()) {
          bases.insert(*it1);
          digsums.insert(digsum(*it1));
        }
      }
      set<long long> diff;

      set_difference(base_->values.begin(), base_->values.end(),
                     bases.begin(), bases.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        base_->values.erase(*it);
        base_change = true;
      }
      diff.clear();
      set_difference(digsum_->values.begin(), digsum_->values.end(),
                     digsums.begin(), digsums.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        digsum_->values.erase(*it);
        digsum_change = true;
      }
      diff.clear();
    }
    if (base_change) base_->Refresh();
    if (digsum_change) digsum_->Refresh();
  }
 private:
  Light* base_;
  Light* digsum_;
};

class ConDigprod : Constraint {
 public:
  ConDigprod(string base, string digprod) {
    base_ = findLight(base);
    digprod_ = findLight(digprod);
    base_->constraints.push_back(this);
    digprod_->constraints.push_back(this);

    append(base_->name());
    append(" has digit prod ");
    append(digprod_->name());
  }

  long long digprod(long long x) {
    int answer = 1;
    while (x > 0) {
      answer *= x % 10;
      x /= 10;
    }
    return answer;
  }
  
  void Refresh() {
    cout << "Inspecting " << name() << endl;
    bool base_change = false;
    bool digprod_change = false;
    if (!base_->exact() && !digprod_->exact()) {
cout << " no data yet\n";

    } else if (!base_->exact() && digprod_->exact()) {
cout << " not enough data yet\n";

    } else if (base_->exact() && !digprod_->exact()) {
cout << " calculating products\n";
      for (set<long long>::iterator it=base_->values.begin();
           it != base_->values.end(); ++it) {
cout << " inserting " << (*it) << " " << digprod(*it) << "\n";
        digprod_->values.insert(digprod(*it));
        digprod_change = true;
      }

    } else if (base_->exact() && digprod_->exact()) {
      set<long long> bases;
      set<long long> digprods;
      for (set<long long>::iterator it1=base_->values.begin();
           it1 != base_->values.end(); ++it1) {
//cout << "looking at base " << (*it1) << "\n";
        if (digprod_->values.find(digprod(*it1)) != 
            digprod_->values.end()) {
          bases.insert(*it1);
          digprods.insert(digprod(*it1));
        }
      }
      set<long long> diff;

      set_difference(base_->values.begin(), base_->values.end(),
                     bases.begin(), bases.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
//cout << "base cannot be " << *it << "\n";
        base_->values.erase(*it);
        base_change = true;
      }
      diff.clear();
      set_difference(digprod_->values.begin(), digprod_->values.end(),
                     digprods.begin(), digprods.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
//cout << "prod cannot be " << *it << "\n";
        digprod_->values.erase(*it);
        digprod_change = true;
      }
      diff.clear();
      assert(digprod_->exact());
      assert(base_->exact());
    }
    if (base_change) base_->Refresh();
    if (digprod_change) digprod_->Refresh();
  }
 private:
  Light* base_;
  Light* digprod_;
};

long long mpow(long long base, long long power) {
  if (power == 1) return base;
  return base * mpow(base, power-1);
}

long long root(long long biggie, long long power) {
  double bg = exp(log((double)biggie)/power);
  long long test = (long long)bg - 2;
  for (int i=0;i<5;i++) {
    if (mpow(test,power) == biggie) return test;
    test++;
  }
  return -1;
}

class ConPower : Constraint {
 public:
  ConPower(string base, string power, int times) {
    base_ = findLight(base);
    power_ = findLight(power);
    base_->constraints.push_back(this);
    power_->constraints.push_back(this);
    times_ = times;

    append(base_->name());
    append(" ^ ");
    append(times_);
    append(" = ");
    append(power_->name());
  }
  void Refresh() {
    cout << "Inspecting " << name() << endl;
    base_->printSummary();
    power_->printSummary();
    bool base_change = false;
    bool power_change = false;
    if (!base_->exact() && !power_->exact()) {
      cout << "  trying ranges " << endl;
      if (mpow(base_->min,times_) < power_->min) {
        while (mpow(base_->min,times_) < power_->min) {
          base_->min++;
        }
        base_change = true;
      }
      if (mpow(base_->min,times_) > power_->min) {
        power_->min = mpow(base_->min,times_);
        power_change = true;
      }

      if (mpow(base_->max,times_) > power_->max) {
        while (mpow(base_->max,times_) > power_->max) {
          base_->max--;
        }
        base_change = true;
      }
      if (mpow(base_->max,times_) < power_->max) {
        power_->max = mpow(base_->max,times_);
        power_change = true;
      }

    } else if (!base_->exact() && power_->exact()) {
      power_->printSummary();
      cout << endl;
      vector<long long> deleteme;
      for (set<long long>::iterator it=power_->values.begin();
           it != power_->values.end(); ++it) {
        long long val = root(*it,times_);
        if (val == -1) {
          deleteme.push_back(*it);
        } else {
          base_->values.insert(val);
        }
      }
      base_change = true;
      for (int i=0;i<deleteme.size(); i++) {
        power_change = true;
        power_->values.erase(deleteme[i]);
      }

    } else if (base_->exact() && !power_->exact()) {
      base_->printSummary();
      cout << endl;
      for (set<long long>::iterator it=base_->values.begin();
           it != base_->values.end(); ++it) {
        power_->values.insert(mpow(*it,times_));
      }
      power_change = true;

    } else if (base_->exact() && power_->exact()) {
      base_->printSummary();
      power_->printSummary();
      vector<long long> deleteme;
      for (set<long long>::iterator it=power_->values.begin();
           it != power_->values.end(); ++it) {
        long long val = root(*it,times_);
 //       cout << val << " ";
        if (val == -1) {
          deleteme.push_back(*it);
        } else if ((base_->values.find(val)) == base_->values.end()) {
          deleteme.push_back(*it);
        }
      }
//      cout << endl;

//      cout << "  removed pieces: " << deleteme.size() << endl;
      for (int i=0;i<deleteme.size(); i++) {
        power_change = true;
        power_->values.erase(deleteme[i]);
      }

      deleteme.clear();

      for (set<long long>::iterator it=base_->values.begin();
           it != base_->values.end(); ++it) {
        if ((power_->values.find(mpow(*it,times_)))
             == power_->values.end()) {
          deleteme.push_back(*it);
        }
      }
//      cout << "  removed pieces: " << deleteme.size() << endl;
      for (int i=0;i<deleteme.size(); i++) {
        base_change = true;
        base_->values.erase(deleteme[i]);
      }
    }
    if (base_change) base_->Refresh();
    if (power_change) power_->Refresh();
  }
 private:
  Light* base_;
  Light* power_;
  int times_;
};

class ConSum : Constraint {
 public:
  ConSum(string base1, string base2, string sum) {
    base1_ = findLight(base1);
    base2_ = findLight(base2);
    sum_ = findLight(sum);
    base1_->constraints.push_back(this);
    base2_->constraints.push_back(this);
    sum_->constraints.push_back(this);

    append(base1_->name());
    append(" + ");
    append(base2_->name());
    append(" = ");
    append(sum_->name());
  }
  void Refresh() {
    cout << "Inspecting " << name() << endl;
    bool base1_change = false;
    bool base2_change = false;
    bool sum_change = false;
    if (!base1_->exact() && !sum_->exact() && !base2_->exact()) {
      cout << "  inspected bounds\n";
      if (base1_->min + base2_->min > sum_->min) {
        sum_->min = base1_->min + base2_->min;
        sum_change = true;
      }
      if (base1_->max + base2_->max < sum_->max) {
        sum_->max = base1_->max + base2_->max;
        sum_change = true;
      }
      if (base1_->min < sum_->min - base2_->max) {
        base1_->min = sum_->min - base2_->max;
        base1_change = true;
      }
      if (base1_->max > sum_->max - base2_->min) {
        base1_->max = sum_->max - base2_->min;
        base1_change = true;
      }
      if (base2_->min < sum_->min - base1_->max) {
        base2_->min = sum_->min - base1_->max;
        base2_change = true;
      }
      if (base2_->max > sum_->max - base1_->min) {
        base2_->max = sum_->max - base1_->min;
        base2_change = true;
      }
    } else if (base1_->exact() && base2_->exact() && !sum_->exact()) {
      for (set<long long>::iterator it1=base1_->values.begin();
           it1 != base1_->values.end(); ++it1) {
      for (set<long long>::iterator it2=base2_->values.begin();
           it2 != base2_->values.end(); ++it2) {
        long long val = *it1+*it2;
        if (val >= sum_->min && val <= sum_->max) {
          sum_->values.insert(val);
          sum_change = true;
        }
      }}
      cout << "  expanded " << sum_->name() << "\n";

    } else if (base1_->exact() && !base2_->exact() && sum_->exact()) {
      for (set<long long>::iterator it1=base1_->values.begin();
           it1 != base1_->values.end(); ++it1) {
      for (set<long long>::iterator it2=sum_->values.begin();
           it2 != sum_->values.end(); ++it2) {
        long long val = *it2-*it1;
        if (val >= base2_->min && val <= base2_->max) {
          base2_->values.insert(val);
          base2_change = true;
        }
      }}
      cout << "  expanded " << base2_->name() << "\n";

    } else if (!base1_->exact() && base2_->exact() && sum_->exact()) {
      for (set<long long>::iterator it1=sum_->values.begin();
           it1 != sum_->values.end(); ++it1) {
      for (set<long long>::iterator it2=base2_->values.begin();
           it2 != base2_->values.end(); ++it2) {
        long long val = *it1-*it2;
        if (val >= base1_->min && val <= base1_->max) {
          base1_->values.insert(val);
          base1_change = true;
        }
      }}
      cout << "  expanded " << base1_->name() << "\n";

    } else if (base1_->exact() && base2_->exact() && sum_->exact()
               && (base1_->values.size() * base2_->values.size() <= 10000) ) {
      base1_->printSummary();
      base2_->printSummary();
      sum_->printSummary();
      set<long long> base1s;
      set<long long> base2s;
      set<long long> sums;
      for (set<long long>::iterator it1=base1_->values.begin();
           it1 != base1_->values.end(); ++it1) {
        for (set<long long>::iterator it2=base2_->values.begin();
             it2 != base2_->values.end(); ++it2) {
          if (sum_->values.find(*it1+*it2) != sum_->values.end()) {
            base1s.insert(*it1);
            base2s.insert(*it2);
            sums.insert(*it1+*it2);
          }
        }
      }
      set<long long> diff;

      set_difference(base1_->values.begin(), base1_->values.end(),
                     base1s.begin(), base1s.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        base1_->values.erase(*it);
        base1_change = true;
      }
      diff.clear();
      set_difference(base2_->values.begin(), base2_->values.end(),
                     base2s.begin(), base2s.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        base2_->values.erase(*it);
        base2_change = true;
      }
      diff.clear();
      set_difference(sum_->values.begin(), sum_->values.end(),
                     sums.begin(), sums.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        sum_->values.erase(*it);
        sum_change = true;
      }
      diff.clear();
      assert(base1_->exact());
      assert(base2_->exact());
      assert(sum_->exact());
    } else {
      cout << " can't do anything.\n";
    }
    cout << stack << " Sum Push\n"; stack++;
    if (base1_change) base1_->Refresh();
    if (base2_change) base2_->Refresh();
    if (sum_change) sum_->Refresh();
    stack--; cout << stack << " Sum Pop\n";
  }
 private:
  Light* base1_;
  Light* base2_;
  Light* sum_;
};

class ConProduct : Constraint {
 public:
  ConProduct(string base1, string base2, string product) {
    base1_ = findLight(base1);
    base2_ = findLight(base2);
    product_ = findLight(product);
    base1_->constraints.push_back(this);
    base2_->constraints.push_back(this);
    product_->constraints.push_back(this);

    append(base1_->name());
    append(" * ");
    append(base2_->name());
    append(" = ");
    append(product_->name());
  }
  void Refresh() {
    cout << "Inspecting " << name() << " : ";
    cout << base1_->values.size() << " ";
    cout << base2_->values.size() << " ";
    cout << product_->values.size() << " ";
    cout << endl;
    bool base1_change = false;
    bool base2_change = false;
    bool product_change = false;
    if (!base1_->exact() && !product_->exact() && !base2_->exact()) {
//cout << "Waaaaaaaaah!\n";
//cout << base1_->name() << " " << base1_->min << " " << base1_->max << endl;
//cout << base2_->name() << " " << base2_->min << " " << base2_->max << endl;
//cout << product_->name() << " " << product_->min << " " << product_->max << endl;
      if (base1_->min * base2_->min > product_->min) {
        product_->min = base1_->min * base2_->min;
//cout << "Raised Product min to " << product_->min << endl;
        product_change = true;
      }
      if (base1_->max * base2_->max < product_->max) {
        product_->max = base1_->max * base2_->max;
//cout << "Raised Product max to " << product_->max << endl;
        product_change = true;
      }
      if (base1_->min * base2_->max < product_->min) {
        base1_->min = product_->min / base2_->max - 10;
        base1_change = true;
      }
      while (base1_->min * base2_->max < product_->min) {
        base1_->min ++;
        base1_change = true;
      }
      if (base1_->max * base2_->min > product_->max) {
        base1_->max = product_->max / base2_->min + 10;
        base1_change = true;
      }
      while (base1_->max * base2_->min > product_->max) {
        base1_->max --;
        base1_change = true;
      }
      if (base2_->min * base1_->max < product_->min) {
        base2_->min = product_->min / base1_->max - 10;
        base2_change = true;
      }
      while (base2_->min * base1_->max < product_->min) {
        base2_->min ++;
        base2_change = true;
      }
      if (base2_->max * base1_->min > product_->max) {
        base2_->max = product_->max / base1_->min + 10;
        base2_change = true;
      }
      while (base2_->max * base1_->min > product_->max) {
        base2_->max --;
        base2_change = true;
      }

    } else if (base1_->exact() && base2_->exact() && !product_->exact()) {
//cout << "Waaaaaaaabh!\n";
      for (set<long long>::iterator it1=base1_->values.begin();
           it1 != base1_->values.end(); ++it1) {
      for (set<long long>::iterator it2=base2_->values.begin();
           it2 != base2_->values.end(); ++it2) {
        product_->values.insert((*it1) * (*it2));
      }}
      product_change = true;

    } else if (base1_->exact() && !base2_->exact() && product_->exact()) {
//cout << "Waaaaaaaach!\n";
      for (set<long long>::iterator it1=base1_->values.begin();
           it1 != base1_->values.end(); ++it1) {
      for (set<long long>::iterator it2=product_->values.begin();
           it2 != product_->values.end(); ++it2) {
        if (*it2 % *it1 == 0)
          base2_->values.insert(*it2 / *it1);
      }}
      base2_change = true;

    } else if (!base1_->exact() && base2_->exact() && product_->exact()) {
//cout << "Waaaaaaaadh!\n";
      for (set<long long>::iterator it1=product_->values.begin();
           it1 != product_->values.end(); ++it1) {
      for (set<long long>::iterator it2=base2_->values.begin();
           it2 != base2_->values.end(); ++it2) {
        if (*it1 % *it2 == 0)
          base1_->values.insert(*it1 / *it2);
      }}
      base1_change = true;

    } else if (base1_->exact() && base2_->exact() && product_->exact()) {
      base1_->printSummary();
      base2_->printSummary();
      product_->printSummary();
      set<long long> base1s;
      set<long long> base2s;
      set<long long> products;
      for (set<long long>::iterator it1=base1_->values.begin();
           it1 != base1_->values.end(); ++it1) {
        for (set<long long>::iterator it2=base2_->values.begin();
             it2 != base2_->values.end(); ++it2) {
          if (product_->values.find(*it1 * *it2) != product_->values.end()) {
            base1s.insert(*it1);
            base2s.insert(*it2);
            products.insert(*it1 * *it2);
          }
        }
      }
      set<long long> diff;

      set_difference(base1_->values.begin(), base1_->values.end(),
                     base1s.begin(), base1s.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        base1_->values.erase(*it);
        base1_change = true;
      }
      diff.clear();
      set_difference(base2_->values.begin(), base2_->values.end(),
                     base2s.begin(), base2s.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        base2_->values.erase(*it);
        base2_change = true;
      }
      diff.clear();
      set_difference(product_->values.begin(), product_->values.end(),
                     products.begin(), products.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        product_->values.erase(*it);
        product_change = true;
      }
      diff.clear();
    }
    cout << "Refreshing...\n";
    if (base1_change) base1_->Refresh();
    if (base2_change) base2_->Refresh();
    if (product_change) product_->Refresh();
  }
 private:
  Light* base1_;
  Light* base2_;
  Light* product_;
};

class ConMod : Constraint {
 public:
  ConMod(string base1, string base2, string mod) {
    base1_ = findLight(base1);
    base2_ = findLight(base2);
    mod_ = findLight(mod);
    base1_->constraints.push_back(this);
    base2_->constraints.push_back(this);
    mod_->constraints.push_back(this);

    append(base1_->name());
    append(" % ");
    append(base2_->name());
    append(" = ");
    append(mod_->name());
  }
  void Refresh() {
    cout << "Inspecting " << name() << endl;
    bool base1_change = false;
    bool base2_change = false;
    bool mod_change = false;
    if (!base1_->exact() && !mod_->exact() && !base2_->exact()) {
      cout << "  no exact yet" << endl;
      if (base2_->max <= mod_->max) {
        mod_->max = base2_->max - 1;
//cout << "       mod_->max = base2_->max - 1  " 
//     << mod_->max << endl;
        mod_change = true;
      }
      if (base1_->max < mod_->max) {
        mod_->max = base1_->max;
//cout << "  mod_->max = base1_->max; "
//     << mod_->max << endl;
        mod_change = true;
      }
      if (base1_->min < mod_->min) {
        base1_->min = mod_->min;
//cout << " base1_->min = mod_->min; "
//     << base1_->min << endl;
        base1_change = true;
      }
      if (base2_->min < mod_->min + 1) {
        base2_->min = mod_->min + 1;
//cout << " base2_->min = mod_->min + 1; " 
//     << base2_->min << endl;
        base2_change = true;
      }
      if (base1_->min > mod_->max && base2_->max > (base1_->max - mod_->min)) {
        base2_->max = base1_->max - mod_->min;
//cout << "   base2_->max = base1_->max - mod_->min; "
//     << base2_->max << endl;
        base2_change = true;
      }

    } else if (base1_->exact() && base2_->exact() && !mod_->exact()) {
      cout << "  deriving " << mod_->name() << endl;
      base1_->printSummary();
      base2_->printSummary();
      for (set<long long>::iterator it1=base1_->values.begin();
           it1 != base1_->values.end(); ++it1) {
      for (set<long long>::iterator it2=base2_->values.begin();
           it2 != base2_->values.end(); ++it2) {
        mod_->values.insert((*it1) % (*it2));
      }}
      mod_change = true;

    } else if (base1_->exact() && !base2_->exact() && mod_->exact()) {
      cout << "  deriving " << base2_->name() << endl;
      for (set<long long>::iterator it1=base1_->values.begin();
           it1 != base1_->values.end(); ++it1) {
//cout << *it1 << " ";
        for (int ig=mod_->min+1; ig <= (*it1 - mod_->min)
              && ig <= base2_->max; ++ig) {
          long long test = (*it1 % ig);
          if (mod_->values.find(test) != mod_->values.end()) {
            base2_->values.insert(ig);
            base2_change = true;
          }
        }
      }
//cout << endl;
//for (set<long long>::iterator it1 = base2_->values.begin();
//   it1 != base2_->values.end(); ++it1) cout << " " << *it1;
//cout << endl;
    } else if (!base1_->exact() && base2_->exact() && mod_->exact()) {
      cout << "  deriving " << base1_->name() << endl;
      for (set<long long>::iterator it1=mod_->values.begin();
           it1 != mod_->values.end(); ++it1) {
      for (set<long long>::iterator it2=base2_->values.begin();
           it2 != base2_->values.end(); ++it2) {
        long long value = (base1_->min / *it2 * *it2 + *it1);
        while (value <= base1_->max) {
          base1_->values.insert(value);
          value += *it2;
        }
      }}
      base1_change = true;

    } else if (base1_->exact() && base2_->exact() && mod_->exact()) {
      cout << "  running through combos " << endl;
      set<long long> base1s;
      set<long long> base2s;
      set<long long> mods;
      for (set<long long>::iterator it1=base1_->values.begin();
           it1 != base1_->values.end(); ++it1) {
        for (set<long long>::iterator it2=base2_->values.begin();
             it2 != base2_->values.end(); ++it2) {
          if (mod_->values.find(*it1 % *it2) != mod_->values.end()) {
            base1s.insert(*it1);
            base2s.insert(*it2);
            mods.insert(*it1 % *it2);
          }
        }
      }
      set<long long> diff;

      set_difference(base1_->values.begin(), base1_->values.end(),
                     base1s.begin(), base1s.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        base1_->values.erase(*it);
        base1_change = true;
      }
      diff.clear();
      set_difference(base2_->values.begin(), base2_->values.end(),
                     base2s.begin(), base2s.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        base2_->values.erase(*it);
        base2_change = true;
      }
      diff.clear();
      set_difference(mod_->values.begin(), mod_->values.end(),
                     mods.begin(), mods.end(), 
                     inserter(diff, diff.end()));
      for (set<long long>::iterator it=diff.begin(); it != diff.end(); ++it) {
        mod_->values.erase(*it);
        mod_change = true;
      }
      diff.clear();
    } else {
      cout << "  not enough known" << endl;
    }
    if (base1_change) base1_->Refresh();
    if (base2_change) base2_->Refresh();
    if (mod_change) mod_->Refresh();
  }
 private:
  Light* base1_;
  Light* base2_;
  Light* mod_;
};

void CellIterator::reset() {
  myvalue = 0;
  while (myvalue < 10 && !(mycell->possible(myvalue))) {
    myvalue++;
  }
}
CellIterator& CellIterator::operator++() {
  if (myvalue == 10) return *this;
  myvalue++;
  while (myvalue < 10 && !(mycell->possible(myvalue))) {
    myvalue++;
  }
  return *this;
}

void MakeLight(string s) {
  Light* l = new Light(s);
  others.push_back(l);
}

void MakeLight(string s, long long min) {
  Light* l = new Light(s, min);
  others.push_back(l);
}

void MakeLight(string s, long long min, long long max) {
  Light* l = new Light(s, min, max);
  others.push_back(l);
}

void sanityCheck() {
  assert(findLight("2D")->hasVal(54043));
  assert(findLight("29A")->hasVal(3179));
  assert(findLight("34A")->hasVal(731));
}

int main() {
  nowhere.black = true;
  nowhere.up = &nowhere;
  nowhere.down = &nowhere;
  nowhere.left = &nowhere;
  nowhere.right = &nowhere;

  for (int pos=0;pos<size*size;pos++) {
    grid[pos].up = &nowhere;
    grid[pos].down = &nowhere;
    grid[pos].left = &nowhere;
    grid[pos].right = &nowhere;
    grid[pos].index = pos;
  }

  for (int pos=0;pos<size*size;pos++) {
    if (pos >= size) {
      grid[pos].up = &grid[pos-size];
      grid[pos-size].down = &grid[pos];
    }
    if (pos % size != 0) {
      grid[pos].left = &grid[pos-1];
      grid[pos-1].right = &grid[pos];
    }
  }

  char gd[][15] = {
"XXX XXXXXX",
"X XXX XXXX",
" XXXXX XX ",
"XXXX XXX X",
"XXX XXX XX",
"XX XXX XXX",
"X XXX XXXX",
" XX XXXXX ",
"XXXX XXX X",
"XXXXXX XXX",
 };

  for (int row=0; row<size; ++row) {
    for (int col=0; col<size; ++col) {
      grid[row*size+col].black = (gd[row][col] == ' ');
    }
  } 

  int number = 1;
  for (int pos=0;pos<size*size;pos++) {
    if (grid[pos].black) continue;
    bool used = false;
    if (!grid[pos].black && grid[pos].up->black && !grid[pos].down->black) {
      GridLight* l = new GridLight(number, false, &grid[pos]);
      down.push_back(l);
      used = true;
    }
    if (!grid[pos].black && grid[pos].left->black && !grid[pos].right->black) {
      GridLight* l = new GridLight(number, true, &grid[pos]);
      across.push_back(l);
      used = true;
    }
    if (used) number++;
  }

  GridLight* t;

  ConMultiple V1 ("2D", "3A", 17);
  ConSum V2 ("14A", "29A", "10A");
  MakeLight("MONE");
  MakeLight("MTWO");
  ConSum V3 ("27A", "2D", "MONE");
  ConSum V4 ("20D", "26D", "MTWO");
  ConSum V5 ("MONE", "MTWO", "11A");
  t = new GridLight(50, true, &grid[4], 3); across.push_back(t);
  t = new GridLight(51, true, &grid[7], 3); across.push_back(t);
  ConSum V8 ("50A", "51A", "14A");
  ConSum V9 ("20A", "6D", "18A");
  ConMultiple V10 ("32D", "22A", 17);
  ConSum V11 ("22D", "26D", "23A");
  t = new GridLight(52, true, &grid[4], 2); across.push_back(t);
  t = new GridLight(53, true, &grid[6], 2); across.push_back(t);
  t = new GridLight(54, true, &grid[8], 2); across.push_back(t);
  MakeLight("PART");
  ConSum V15 ("52A", "53A", "PART");
  ConSum V16 ("PART", "54A", "24A");
  ConMultiple V17 ("14A", "27A", 9);
  ConMultiple V18 ("22A", "29A", 17);
  ConSum V19 ("1A", "28D", "31A");
  ConProduct V20 ("27A", "7D", "33A");
  ConMultiple V21 ("34A", "17D", 2);
  ConDigsum V22 ("25A", "1D");
  ConMultiple V23 ("29A", "2D", 17);
  ConSum V24 ("22A", "11D", "5D");
  ConProduct V25 ("4D", "30D", "11D");
  ConSum V26 ("17D", "12D", "29A");
  MakeLight("PARTY");
  ConSum V27 ("24A", "3D", "PARTY");
  ConSum V28 ("PARTY", "9D", "14D");
  ConSum V290 ("21A", "26A", "16D");
  ConSum V29 ("22A", "17D", "14A");
  ConSum V30 ("8A", "24D", "19D");
  MakeLight("PROD");
  ConProduct V31 ("17D", "32D", "PROD");
  ConSum V32 ("27A", "20D", "PROD");
  MakeLight("ZERO", 0);
  ConMod V33 ("23D", "32D", "ZERO");
  MakeLight("SUMMY");
  ConSum V34 ("15A", "19A", "SUMMY");
  ConSum V35 ("SUMMY", "20A", "25D");
  MakeLight("PRODDY");
  ConProduct V36 ("29D", "30D", "PRODDY");
  ConMultiple V37 ("26D", "PRODDY", 7);
  ConMultiple V38 ("13A", "28D", 12);
  // 

  for (int pos=0;pos<size*size;pos++) {
    if (!grid[pos].black && grid[pos].up->black && !grid[pos].down->black) {
      grid[pos].setPossible(0, false);
    }
    if (!grid[pos].black && grid[pos].left->black && !grid[pos].right->black) {
      grid[pos].setPossible(0, false);
    }
  }

  for (int i=0;i<across.size(); ++i){
    across[i]->Refresh();
  }
  for (int i=0;i<down.size(); ++i){
    down[i]->Refresh();
  }
  for (int i=0;i<others.size(); ++i){
    others[i]->Refresh();
  }

  cout << "\n";
  for (int row=0; row<size; ++row) {
    for (int col=0; col<size; ++col) {
      if (grid[row*size+col].black) 
        cout << '.';
      else
        cout << grid[row*size+col].value();
    }
    cout << "    ";
    for (int col=0; col<size; ++col) {
      if (grid[row*size+col].black) 
        cout << '.';
      else
        cout << grid[row*size+col].certain();
    }
    cout << "\n";
  } 

  for (int i=0; i<across.size(); ++i) {
    across[i]->printRange();
  }
  for (int i=0; i<down.size(); ++i) {
    down[i]->printRange();
  }
  for (int i=0; i<others.size(); ++i) {
    others[i]->printRange();
  }
  cout << "\n";






// cleanup
  for (int i=0; i<across.size(); ++i) {
    delete across[i];
  }
  for (int i=0; i<down.size(); ++i) {
    delete down[i];
  }
}
