public static int EstimatedEuclideanDistanceFromX10(pos p1,pos p2)
 {
     return EstimatedEuclideanDistanceFromX10(p1.r,p1.c,p2.r,p2.c);
 }
 /*public int RotateDir(int dir,bool clockwise){ return RotateDir(dir,clockwise,1); }
 public int RotateDir(int dir,bool clockwise,int times){
     if(dir == 5){ return 5; }
     for(int i=0;i<times;++i){
         switch(dir){
         case 7:
             dir = clockwise?8:4;
             break;
         case 8:
             dir = clockwise?9:7;
             break;
         case 9:
             dir = clockwise?6:8;
             break;
         case 4:
             dir = clockwise?7:1;
             break;
         case 6:
             dir = clockwise?3:9;
             break;
         case 1:
             dir = clockwise?4:2;
             break;
         case 2:
             dir = clockwise?1:3;
             break;
         case 3:
             dir = clockwise?2:6;
             break;
         default:
             return 0;
         }
     }
     return dir;
 }
 public pos PosInDir(int r,int c,int dir){ return PosInDir(new pos(r,c),dir); }
 public pos PosInDir(pos p,int dir){
     switch(dir){
     case 7:
         return new pos(p.r-1,p.c-1);
     case 8:
         return new pos(p.r-1,p.c);
     case 9:
         return new pos(p.r-1,p.c+1);
     case 4:
         return new pos(p.r,p.c-1);
     case 5:
         return p;
     case 6:
         return new pos(p.r,p.c+1);
     case 1:
         return new pos(p.r+1,p.c-1);
     case 2:
         return new pos(p.r+1,p.c);
     case 3:
         return new pos(p.r+1,p.c+1);
     default:
         return new pos(-1,-1);
     }
 }*/
 public void RemoveDiagonals()
 {
     List<pos> walls = new List<pos>();
     for(int i=1;i<H-2;++i){
         for(int j=1;j<W-2;++j){
             if(ConvertedChar(map[i,j]) == "." && ConvertedChar(map[i,j+1]) == "#"){
                 if(ConvertedChar(map[i+1,j]) == "#" && ConvertedChar(map[i+1,j+1]) == "."){
                     walls.Add(new pos(i,j+1));
                     walls.Add(new pos(i+1,j));
                 }
             }
             if(ConvertedChar(map[i,j]) == "#" && ConvertedChar(map[i,j+1]) == "."){
                 if(ConvertedChar(map[i+1,j]) == "." && ConvertedChar(map[i+1,j+1]) == "#"){
                     walls.Add(new pos(i,j));
                     walls.Add(new pos(i+1,j+1));
                 }
             }
             if(walls.Count > 0){
                 pos wall0 = walls[0];
                 pos wall1 = walls[1];
                 while(walls.Count > 0){
                     pos p = walls[Roll(walls.Count)-1];
                     walls.Remove(p);
                     int direction_of_other_wall = 0;
                     string[] rotated = new string[8];
                     for(int ii=0;ii<8;++ii){
                         rotated[ii] = Map(PosInDir(p,RotateDir(8,true,ii)));
                         pos other_wall = new pos(-1,-1);
                         if(p.r == wall0.r && p.c == wall0.c){
                             other_wall = wall1;
                         }
                         else{
                             other_wall = wall0;
                         }
                         if(PosInDir(p,RotateDir(8,true,ii)).r == other_wall.r && PosInDir(p,RotateDir(8,true,ii)).c == other_wall.c){
                             direction_of_other_wall = RotateDir(8,true,ii);
                         }
                     }
                     int successive_walls = 0;
                     for(int ii=5;ii<8;++ii){
                         if(ConvertedChar(rotated[ii]) == "#"){
                             successive_walls++;
                         }
                         else{
                             successive_walls = 0;
                         }
                     }
                     for(int ii=0;ii<8;++ii){
                         if(ConvertedChar(rotated[ii]) == "#"){
                             successive_walls++;
                         }
                         else{
                             successive_walls = 0;
                         }
                         if((successive_walls == 4) || (ConvertedChar(Map(PosInDir(p,RotateDir(direction_of_other_wall,true,3)))) == "#"
                         && ConvertedChar(Map(PosInDir(p,RotateDir(direction_of_other_wall,true,4)))) == "#"
                         && ConvertedChar(Map(PosInDir(p,RotateDir(direction_of_other_wall,true,5)))) == "#")){
                             map[p.r,p.c] = "i";
                             if(IsLegal(p.r,p.c)){
                                 walls.Clear();
                             }
                             else{
                                 map[p.r,p.c] = "#";
                             }
                             break;
                         }
                     }
                 }
             }
         }
     }
 }
 public bool Equals(pos tgt)
 {
     return tgt != null && r == tgt.r && c == tgt.c;
 }
 public bool IsCorridor(pos p)
 {
     if(!IsRoom(p) && ConvertedChar(Map(p)) != "#"){
         return true;
     }
     return false;
 }
 public bool IsRoom(pos p)
 {
     if(!IsRoomOrGenericFloor(Map(p))){
         return false;
     }
     for(int i=2;i<=8;i+=2){
         if(IsRoomOrGenericFloor(Map(PosInDir(p,i))) && IsRoomOrGenericFloor(Map(PosInDir(p,RotateDir(i,true,1))))
         && IsRoomOrGenericFloor(Map(PosInDir(p,RotateDir(i,true,2))))){
             return true;
         }
     }
     return false;
 }
 public string FindFloorType(int r,int c)
 {
     pos p = new pos(r,c);
     if(ConvertedChar(Map(p)) != "."){
         return ConvertedChar(Map(p));
     }
     if(IsRoom(r,c)){
         //int num_walls = ForEachDirection(r,c,ch => ConvertedChar(ch)=="#",true);
         int num_walls = 0;
         for(int i=1;i<=8;++i){
             int dir = i;
             if(dir == 5){
                 dir = 9;
             }
             if(!IsRoom(PosInDir(p,dir))){
                 ++num_walls;
             }
         }
         if(num_walls == 0){
             return "r";
         }
         int num_dirs_with_walls = 0;
         for(int i=2;i<=8;i+=2){
             if(!IsRoom(PosInDir(p,i)) && !IsRoom(PosInDir(p,RotateDir(i,true,1)))
             && !IsRoom(PosInDir(p,RotateDir(i,false,1)))){
                 num_dirs_with_walls++;
             }
         }
         if(num_walls == 3 && num_dirs_with_walls == 1){
             return "E";
         }
         if(num_walls == 5 && num_dirs_with_walls == 2){
             return "c";
         }
     }
     else{
         if(ConvertedChar(Map(PosInDir(p,8))) == "#" && ConvertedChar(Map(PosInDir(p,2))) == "#"){
             return "h";
         }
         if(ConvertedChar(Map(PosInDir(p,4))) == "#" && ConvertedChar(Map(PosInDir(p,6))) == "#"){
             return "v";
         }
         if(ConvertedChar(Map(PosInDir(p,1))) == "#" && ConvertedChar(Map(PosInDir(p,9))) == "#"){
             return "i";
         }
         if(ConvertedChar(Map(PosInDir(p,7))) == "#" && ConvertedChar(Map(PosInDir(p,3))) == "#"){
             return "i";
         }
     }
     return "N";
 }
 public string Map(pos p)
 {
     return map[p.r,p.c];
 }
 public bool CreateCorridor(int rr,int rc,int count,int dir)
 {
     bool result = false;
     pos endpoint = new pos(rr,rc);
     pos potential_endpoint;
     List<pos> chain = null;
     if(count > 1){
         chain = new List<pos>();
     }
     int tries = 0;
     while(count > 0 && tries < 100){ //assume there's no room for a corridor if it fails 25 times in a row
         tries++;
         rr = endpoint.r;
         rc = endpoint.c;
         potential_endpoint = endpoint;
         if(chain != null && chain.Count > 0){ //reroll direction ONLY after the first part of the chain.
             dir = Roll(4)*2;
         }
         //int length = Roll(5)+2;	//again, these 2 lines are still accurate, but have been generalized for
         //if(CoinFlip()){ length += 8; } //testing purposes below:
         int length = Roll(corridor_length_max - (corridor_length_min-1)) + (corridor_length_min-1);
         if(CoinFlip()){ length += corridor_length_addition; }
         switch(dir){
         case 8: //make them all point either down..
             dir = 2;
             rr -= length-1;
             potential_endpoint.r = rr;
             break;
         case 2:
             potential_endpoint.r += length-1;
             break;
         case 4: //..or right
             dir = 6;
             rc -= length-1;
             potential_endpoint.c = rc;
             break;
         case 6:
             potential_endpoint.c += length-1;
             break;
         }
         switch(dir){
         case 2:
         {
             bool valid_position = true;
             for(int i=rr;i<rr+length;++i){
                 if(!BoundsCheck(i,rc)){
                     valid_position = false;
                     break;
                 }
                 if(true/*corridor_chains_overlap_themselves == false*/){
                     if(chain != null && chain.Count > 0 && i != endpoint.r && chain.Contains(new pos(i,rc))){
                         valid_position = false;
                         break;
                     }
                 }
             }
             if(valid_position){
                 string[] submap = new string[length+2];
                 for(int i=0;i<length+2;++i){
                     submap[i] = map[i+rr-1,rc];
                 }
                 bool good = true;
                 for(int i=0;i<length;++i){
                     if(map[i+rr,rc] == "h" || map[i+rr,rc-1] == "h" || map[i+rr,rc+1] == "h"){
                         map[i+rr,rc] = "i";
                     }
                     else{
                         switch(map[i+rr,rc]){
                         case "i":
                         case "E":
                         case "r":
                             break;
                         case "c":
                             if(allow_all_corner_connections == false){
                                 good = false;
                             }
                             break;
                         case "X":
                             good = false;
                             break;
                         default:
                             map[i+rr,rc] = "v";
                             break;
                         }
                     }
                 }
                 if(good && map[rr-1,rc] == "h"){ map[rr-1,rc] = "i"; }
                 if(good && map[rr+length,rc] == "h"){ map[rr+length,rc] = "i"; }
                 for(int i=rr-1;i<rr+length+1 && good;++i){ //note that it doesn't check the bottom or right, since
                     for(int j=rc-1;j<rc+2;++j){ //they are checked by the others
                         if(i != rr+length && j != rc+1){
                             if(ConvertedChar(map[i,j]) == "."){
                                 if(ConvertedChar(map[i,j+1]) == "."
                                    && ConvertedChar(map[i+1,j]) == "."
                                    && ConvertedChar(map[i+1,j+1]) == "."){
                                     good = false;
                                     break;
                                 }
                             }
                         }
                         if(!IsLegal(i,j)){
                             good = false;
                             break;
                         }
                     }
                 }
                 /*Draw();
     if(chain != null){
     foreach(pos p in chain){
     Console.SetCursorPosition(25+p.c,p.r);
     if(ConvertedChar(map[p.r,p.c]) == "."){
     Console.Write("X");
     }
     else{
     Console.Write("x");
     }
     }
     }
     Console.ReadKey(true);*/
                 if(!good){ //if this addition is illegal...
                     for(int i=0;i<length+2;++i){
                         map[i+rr-1,rc] = submap[i];
                     }
                 }
                 else{
                     count--;
                     tries = 0;
                     if(chain != null){
                         if(chain.Count == 0){
                             chain.Add(endpoint);
                         }
                         for(int i=rr;i<rr+length;++i){
                             pos p = new pos(i,rc);
                             if(!(p.Equals(endpoint))){
                                 chain.Add(p);
                             }
                         }
                     }
                     endpoint = potential_endpoint;
                     result = true;
                 }
             }
             break;
         }
         case 6:
         {
             bool valid_position = true;
             for(int j=rc;j<rc+length;++j){
                 if(!BoundsCheck(rr,j)){
                     valid_position = false;
                     break;
                 }
                 if(true/*corridor_chains_overlap_themselves == false*/){
                     if(chain != null && chain.Count > 0 && j != endpoint.c && chain.Contains(new pos(rr,j))){
                         valid_position = false;
                         break;
                     }
                 }
             }
             if(valid_position){
                 string[] submap = new string[length+2];
                 for(int j=0;j<length+2;++j){
                     submap[j] = map[rr,j+rc-1];
                 }
                 bool good = true;
                 for(int j=0;j<length;++j){
                     if(map[rr,j+rc] == "v" || map[rr-1,j+rc] == "v" || map[rr+1,j+rc] == "v"){
                         map[rr,j+rc] = "i";
                     }
                     else{
                         switch(map[rr,j+rc]){
                         case "i":
                         case "E":
                         case "r":
                             break;
                         case "c":
                             if(allow_all_corner_connections == false){
                                 good = false;
                             }
                             break;
                         case "X":
                             good = false;
                             break;
                         default:
                             map[rr,j+rc] = "h";
                             break;
                         }
                     }
                 }
                 if(good && map[rr,rc-1] == "v"){ map[rr,rc-1] = "i"; }
                 if(good && map[rr,rc+length] == "v"){ map[rr,rc+length] = "i"; }
                 for(int i=rr-1;i<rr+2 && good;++i){ //note that it doesn't check the bottom or right, since
                     for(int j=rc-1;j<rc+length+1;++j){ //they are checked by the others
                         if(i != rr+1 && j != rc+length){
                             if(IsCorridor(map[i,j])){
                                 if(IsCorridor(map[i,j+1])
                                    && IsCorridor(map[i+1,j])
                                    && IsCorridor(map[i+1,j+1])){
                                     good = false;
                                     break;
                                 }
                             }
                         }
                         if(!IsLegal(i,j)){
                             good = false;
                             break;
                         }
                     }
                 }
                 /*Draw();
     if(chain != null){
     foreach(pos p in chain){
     Console.SetCursorPosition(25+p.c,p.r);
     if(ConvertedChar(map[p.r,p.c]) == "."){
     Console.Write("X");
     }
     else{
     Console.Write("x");
     }
     }
     }
     Console.ReadKey(true);*/
                 if(!good){ //if this addition is illegal...
                     for(int j=0;j<length+2;++j){
                         map[rr,j+rc-1] = submap[j];
                     }
                 }
                 else{
                     count--;
                     tries = 0;
                     if(chain != null){
                         if(chain.Count == 0){
                             chain.Add(endpoint);
                         }
                         for(int j=rc;j<rc+length;++j){
                             pos p = new pos(rr,j);
                             if(!(p.Equals(endpoint))){
                                 chain.Add(p);
                             }
                         }
                     }
                     endpoint = potential_endpoint;
                     result = true;
                 }
             }
             break;
         }
         }
     }
     return result;
 }
 public static pos PosInDir(pos p,int dir)
 {
     switch(dir){
     case 7:
         return new pos(p.r-1,p.c-1);
     case 8:
         return new pos(p.r-1,p.c);
     case 9:
         return new pos(p.r-1,p.c+1);
     case 4:
         return new pos(p.r,p.c-1);
     case 5:
         return p;
     case 6:
         return new pos(p.r,p.c+1);
     case 1:
         return new pos(p.r+1,p.c-1);
     case 2:
         return new pos(p.r+1,p.c);
     case 3:
         return new pos(p.r+1,p.c+1);
     default:
         return new pos(-1,-1);
     }
 }
 public void AddFirePits()
 {
     int num_firepits = 0;
     switch(Roll(5)){
     case 1:
         num_firepits = 1;
         break;
     case 2:
         num_firepits = Roll(4)+1;
         break;
     }
     for(int i=0;i<num_firepits;++i){
         int tries = 0;
         for(bool done=false;!done && tries < 100;++tries){
             int rr = Roll(H-4) + 1;
             int rc = Roll(W-4) + 1;
             if(ConvertedChar(map[rr,rc]) == "."){
                 bool floors = true;
                 pos temp = new pos(rr,rc);
                 for(int ii=1;ii<=8;++ii){
                     int dir = ii;
                     if(dir == 5){
                         dir = 9;
                     }
                     if(ConvertedChar(Map(PosInDir(temp,dir))) != "."){
                         floors = false;
                         break;
                     }
                 }
                 if(floors){
                     map[rr,rc] = "0";
                     done = true;
                 }
             }
         }
     }
 }