[Question]
  [
## The challenge
Your program or function will accept a single string input from STDIN or a function parameter. You can assume the input will contain only alphabetic characters (a-zA-Z), spaces, and full stops. Input is case insensitive, so you should treat 'a' exactly the same as you would treat 'A'.
For each character in the string, you will output a representation of a building as per the following specification.
Each building must have a roof, designated by an underscore on the top line then a slash, space, backslash on the second line.
```
 _
/ \
```
You will then have a number of floors, matching the letter number (a=1, b=2, c=3 etc.) which are represented by a wall (|) on each side and a space in the middle. The bottom floor (and only the bottom floor) should have a foundation, which is an underscore between the walls. Like this...
```
|_|
```
So for example, 'b' would look like this
```
 _
/ \
| |
|_|
```
Now, we know that very tall, narrow buildings cannot stand and must get wider at the base, so no building can stand more than three storeys high without some additional support. So every three levels (no less) you should add a 'widening layer'. The widening layer consists of a slash and backslash directly above the walls of the section below it, and the section below should be two spaces wider than the section above. The extra layer does not count towards the height of the building.
Buildings should not overlap but should not have any unnecessary spaces between them, and the ground is always flat so all buildings should have their base on the same level.
For example, 'abcdefga' will look like this.
```
                           _
                          / \
                     _    | |
                _   / \   | |
           _   / \  | |   | |
          / \  | |  | |  /   \
       _  | |  | |  | |  |   |
    _ / \ | |  | | /   \ |   |
 _ / \| | | | /   \|   | |   |  _
/ \| || |/   \|   ||   |/     \/ \
|_||_||_||___||___||___||_____||_|
```
Spaces in the string input should be represented by a double space.
Full stops in the string input should be represented by rubble like this.
```
/\/\
```
## Further examples
Input = `Hello world.`
Output =
```
                                                   _                                                  
                                                  / \                                                 
                                                  | |                                                 
                                                  | |                                                 
                                                  | |                                                 
                                                 /   \                                                
                                                 |   |                                                
                                                 |   |                       _                        
                                                 |   |                      / \                       
                                                /     \                     | |                       
                                                |     |                     | |                       
                                   _            |     |          _          | |                       
                                  / \           |     |         / \        /   \                      
                                  | |          /       \        | |        |   |                      
                                  | |          |       |        | |        |   |                      
                _        _        | |          |       |        | |        |   |        _             
               / \      / \      /   \         |       |       /   \      /     \      / \            
               | |      | |      |   |        /         \      |   |      |     |      | |            
               | |      | |      |   |        |         |      |   |      |     |      | |            
               | |      | |      |   |        |         |      |   |      |     |      | |            
   _          /   \    /   \    /     \       |         |     /     \    /       \    /   \           
  / \         |   |    |   |    |     |      /           \    |     |    |       |    |   |           
  | |         |   |    |   |    |     |      |           |    |     |    |       |    |   |           
  | |         |   |    |   |    |     |      |           |    |     |    |       |    |   |           
  | |    _   /     \  /     \  /       \     |           |   /       \  /         \  /     \          
 /   \  / \  |     |  |     |  |       |    /             \  |       |  |         |  |     |   _      
 |   |  | |  |     |  |     |  |       |    |             |  |       |  |         |  |     |  / \     
 |   |  | |  |     |  |     |  |       |    |             |  |       |  |         |  |     |  | |     
 |   |  | | /       \/       \/         \   |             | /         \/           \/       \ | |     
/     \/   \|       ||       ||         |  /               \|         ||           ||       | | |     
|     ||   ||       ||       ||         |  |               ||         ||           ||       |/   \    
|_____||___||_______||_______||_________|  |_______________||_________||___________||_______||___|/\/\
```
Input = `lorem ipsum`
```
                                                                                             _                  
                                                                                            / \                 
                                                                              _             | |                 
                                                                             / \            | |                 
                          _                                                  | |            | |                 
                         / \                                                 | |           /   \                
                         | |                                    _            | |           |   |                
                         | |                                   / \          /   \          |   |                
              _          | |                                   | |          |   |          |   |                
             / \        /   \                                  | |          |   |         /     \               
             | |        |   |              _                   | |          |   |         |     |         _     
             | |        |   |             / \                 /   \        /     \        |     |        / \    
    _        | |        |   |             | |                 |   |        |     |        |     |        | |    
   / \      /   \      /     \            | |                 |   |        |     |       /       \       | |    
   | |      |   |      |     |            | |                 |   |        |     |       |       |       | |    
   | |      |   |      |     |           /   \               /     \      /       \      |       |      /   \   
   | |      |   |      |     |           |   |        _      |     |      |       |      |       |      |   |   
  /   \    /     \    /       \          |   |       / \     |     |      |       |     /         \     |   |   
  |   |    |     |    |       |          |   |       | |     |     |      |       |     |         |     |   |   
  |   |    |     |    |       |         /     \      | |    /       \    /         \    |         |    /     \  
  |   |    |     |    |       |         |     |      | |    |       |    |         |    |         |    |     |  
 /     \  /       \  /         \   _    |     |     /   \   |       |    |         |   /           \   |     |  
 |     |  |       |  |         |  / \   |     |     |   |   |       |    |         |   |           |   |     |  
 |     |  |       |  |         |  | |  /       \    |   |  /         \  /           \  |           |  /       \ 
 |     |  |       |  |         |  | |  |       |    |   |  |         |  |           |  |           |  |       | 
/       \/         \/           \ | |  |       |   /     \ |         |  |           | /             \ |       | 
|       ||         ||           |/   \ |       |   |     | |         |  |           | |             | |       | 
|       ||         ||           ||   |/         \  |     |/           \/             \|             |/         \
|_______||_________||___________||___||_________|  |_____||___________||_____________||_____________||_________|
```
Input = `a.a.a.x.x.x.a.a.a`
```
                             _                    _                    _                             
                            / \                  / \                  / \                            
                            | |                  | |                  | |                            
                            | |                  | |                  | |                            
                            | |                  | |                  | |                            
                           /   \                /   \                /   \                           
                           |   |                |   |                |   |                           
                           |   |                |   |                |   |                           
                           |   |                |   |                |   |                           
                          /     \              /     \              /     \                          
                          |     |              |     |              |     |                          
                          |     |              |     |              |     |                          
                          |     |              |     |              |     |                          
                         /       \            /       \            /       \                         
                         |       |            |       |            |       |                         
                         |       |            |       |            |       |                         
                         |       |            |       |            |       |                         
                        /         \          /         \          /         \                        
                        |         |          |         |          |         |                        
                        |         |          |         |          |         |                        
                        |         |          |         |          |         |                        
                       /           \        /           \        /           \                       
                       |           |        |           |        |           |                       
                       |           |        |           |        |           |                       
                       |           |        |           |        |           |                       
                      /             \      /             \      /             \                      
                      |             |      |             |      |             |                      
                      |             |      |             |      |             |                      
                      |             |      |             |      |             |                      
                     /               \    /               \    /               \                     
 _      _      _     |               |    |               |    |               |     _      _      _ 
/ \    / \    / \    |               |    |               |    |               |    / \    / \    / \
|_|/\/\|_|/\/\|_|/\/\|_______________|/\/\|_______________|/\/\|_______________|/\/\|_|/\/\|_|/\/\|_|
```
## Rules
* Of course this is code golf, lowest score in bytes wins
* Standard loophole rules apply
* Any number of additional blank lines before or after the output are allowed
* You can choose to output the entire result in one string or offer the output as an array where each element represents one line of output, or send to STDOUT
## Note
This is my first post to PPCG, so please go easy on me. It's been through the sandbox. Any negative points or possible improvements please post as a comment and I'll do what I can
  
[Answer]
## JavaScript (ES6), ~~330~~ ~~326~~ ... ~~315~~ 309 bytes
Builds the ASCII art recursively, starting with the bottom floor and applying several regular expressions between each stage:
```
(a,l,R=(E,b)=>E.split`:`.map((e,i)=>l=(l||a).replace(RegExp(e,'g'),b?b.split`:`[i]:n=>(x=(n.charCodeAt()-65)%32)<0?x+1?'/y/y':n+n:x%3+'_'.repeat((x/3<<1)+1)+0)))=>(L=l)?(R('/y:_:/xy:1:2:/xx(x+)y:0(x+)0:3','  :x: _ :3:1: 2$10 :/$1y:0'),L==l?(l=a.join`
`,R('\\d:x:y','|: :\\'),l):f([l].concat(a),l)):f(R('.'),l)
```
### How it works
**1) Bottom floor**
We start by translating the input string into a bottom floor such as:
```
"ab cd.df.hcab"  -->  "0_01_0  2_00___0/y/y0___02___0/y/y1_____02_00_01_0"
```
where:
* `y` is a shorter alias for the backslash (which requires escaping)
* The digit (`0`, `1` or `2`) just before a sequence of `_` is the left wall of the building. It represents the number of walls that must be placed above it before the next 'widening layer'.
* The digit after a sequence of `_` is the right wall of the building and is always set to `0`.
**2) Regular expressions applied between each stage**
The recursive process consists of applying 9 replacements on the previous floor, using the following regular expressions:
1. `/\/y/g` => `" "` (remove the rubble)
2. `/_/g` => `"x"` (replace the foundation or the top of the building with a solid block)
3. `/\/xy/g` => `" _ "` (replace the last widening layer with the top of the building)
4. `/1/g` => `"3"` (temporarily replace `1` with `3` -- see last step)
5. `/2/g` => `"1"` (replace `2` with `1`)
6. `/\/xx(x+)y/g` => `" 2$10 "` (replace a widening layer with a new, narrower wall)
7. `/0(x+)0/g` => `"/$1y"` (replace the top of the wall with a widening layer)
8. `/3/g` => `"0"` (replace `3` with `0`)
For instance, here are the successive transformations of `2___0` (bottom floor generated by a `'f'`):
```
"2___0" > "1xxx0" > "0xxx0" > "/xxxy" > " 2x0 " > " 1x0 " > " 0x0 " > " /xy " > "  _  "
                                                                                   _   
                                                                        /xy       /xy  
                                                              0x0       0x0       0x0  
                                                    1x0       1x0       1x0       1x0  
                                          2x0       2x0       2x0       2x0       2x0  
                               /xxxy     /xxxy     /xxxy     /xxxy     /xxxy     /xxxy 
                     0xxx0     0xxx0     0xxx0     0xxx0     0xxx0     0xxx0     0xxx0 
           1xxx0     1xxx0     1xxx0     1xxx0     1xxx0     1xxx0     1xxx0     1xxx0 
 2___0     2___0     2___0     2___0     2___0     2___0     2___0     2___0     2___0 
```
***NB**: The top of the building is then replaced by a `x`. This is not shown in the above diagram.*
**3) Regular expressions applied to the final result**
The recursion stops when there's nothing more to replace, which means that we are beyond the top of the highest building.
We now need to clean up everything with yet another few regular expressions:
1. `/\d/g` => `"|"` (replace digits with pipes)
2. `/x/g` => `" "` (replace solid blocks with spaces)
3. `/y/g` => `"\"` (replace `y` with backslashes)
For instance:
```
  _            _  
 /xy          / \ 
 0x0          | | 
 1x0          | | 
 2x0   -->    | | 
/xxxy        /   \
0xxx0        |   |
1xxx0        |   |
2___0        |___|
```
### Demo
```
let f =
(a,l,R=(E,b)=>E.split`:`.map((e,i)=>l=(l||a).replace(RegExp(e,'g'),b?b.split`:`[i]:n=>(x=(n.charCodeAt()-65)%32)<0?x+1?'/y/y':n+n:x%3+'_'.repeat((x/3<<1)+1)+0)))=>(L=l)?(R('/y:_:/xy:1:2:/xx(x+)y:0(x+)0:3','  :x: _ :3:1: 2$10 :/$1y:0'),L==l?(l=a.join`
`,R('\\d:x:y','|: :\\'),l):f([l].concat(a),l)):f(R('.'),l)
console.log(f('ab cd.df.hcab'));
```
*Contributors:*  
*4 bytes saved thanks to Hedi*  
*8 bytes saved thanks to Not that Charles*
[Answer]
# PHP, ~~386~~ ~~376~~ ~~367~~ ~~364~~ ~~362~~ ~~358~~ 356 bytes
first approach; may still be golfable.
```
foreach(str_split($argv[1])as$c)for($n=28,$w='.'!=$c?1+2*ceil(1/3*$n=31&ord($c)):4,$p=$y=0;$y<36;){$s=str_pad("",$w,$y||!$n?" ":_);if($n>26&&!$y){$s="/\\/\\";$n=-1;}elseif($n-->0){$s[$p]=$s[$w-$p-1]="|";if($n%3<1){$o[$y++].=$s;$s=str_pad("",$w);$s[$p]="/";$s[$w-++$p]="\\";}}$o[$y++].=$s;if(!$n)$o[$y++].=str_pad(_,$w," ",2);}for($y=36;$y--;)echo"$o[$y]
";
```
**PHP, ~~366~~ ~~362~~ ~~361~~ ~~360~~ 357 bytes**
similar approach with a subfunction:
```
function a($p,$r){global$o,$w,$y;$o[$y++].=str_pad(str_pad($r[0],2*$p,$r[1]).$r[2],$w," ",2);}foreach(str_split($argv[1])as$i=>$c)for($n=28,$w='.'!=$c?1+2*$p=ceil(1/3*$n=31&ord($c)):$p=4,$y=0;$y<36;)if($n>26&&!$y)$o[$n=$y++].="/\\/\\";elseif($n-->0){a($p,$y?"| |":"|_|");if($n%3<1)a($p--,"/ \\");if(!$n)a(1," _");}else a(0,"");for($y=36;$y--;)echo"$o[$y]
";
```
**breakdown** for the second approach
```
function a($p,$r)
{
    global$o,$w,$y;
    $o[$y++].=                  // 3. add result to current line, increase line counter
        str_pad(                // 2. pad ...
        str_pad($r[0],2*$p,$r[1]).$r[2]     // 1. A + inner width(=2*$p-1) times B + C
        ,$w," ",2);             // ... to $w with blanks on both sides # 2==STR_PAD_BOTH
}
foreach(str_split($argv[1])as$i=>$c)
    for(
    $n=28,
    $w='.'!=$c                          // $w=total width
        ?1+2*$p=ceil(1/3*$n=31&ord($c)) // $n=storey count, $p=(inner width+1)/2
        :$p=4                           // $n=28, $p <= $w=4 for rubble
    ,
    $y=0;$y<36;)                        // $y=line counter
        if($n>26&&!$y)
            $o[$n=$y++].="/\\/\\";      // bottom line=rubble, $n=0
        elseif($n-->0)
        {
            a($p,$y?"| |":"|_|");       // add storey
            if($n%3<1)a($p--,"/ \\");   // add widening layer/roof
            if(!$n)a(1," _");           // add roof top
        }
        else
            a(0,"");                    // idk why str_pad doesn´t yield a warning here
for($y=36;$y--;)if($s=rtrim($o[$y]))echo"$s\n"; // output
```
---
+16 bytes if leading newlines are not allowed:  
Replace `echo"$o[$y]\n;` with `if($s=rtrim($o[$y]))echo"$s\n";`.
-3 bytes for any of `;<=>?[\]^_{|}~` as rubble:
Replace 1) `($n=31&ord($c))` with `$n`, 2) `$n=28,$w='.'!=$c` with `($n=31&ord($c))<27` and 3) `4` with `($n=28)/7`.
Another -8 for `>`, `^` or `~` as rubble: Undo 3)
[Answer]
# Pyth, ~~93~~ 79 bytes
```
K"/\\"j_.tsm?hJxGdC_m.[hyNk\ +\_mj*hy/k4?nkJ\ \_?%k4"||"Kh=+J=Nh/J3[F*2|@d;Krz0
```
[Try it online.](http://pyth.herokuapp.com/?code=K%22%2F%5C%5C%22j_.tsm%3FhJxGdC_m.%5BhyNk%5C%20%2B%5C_mj*hy%2Fk4%3FnkJ%5C%20%5C_%3F%25k4%22%7C%7C%22Kh%3D%2BJ%3DNh%2FJ3%5BF*2%7C%40d%3BKrz0&input=Hello+world.&test_suite=1&test_suite_input=abcdefga%0AHello+world.%0Alorem+ipsum%0Aa.a.a.x.x.x.a.a.a&debug=0) [Test suite.](http://pyth.herokuapp.com/?code=K%22%2F%5C%5C%22j_.tsm%3FhJxGdC_m.%5BhyNk%5C%20%2B%5C_mj*hy%2Fk4%3FnkJ%5C%20%5C_%3F%25k4%22%7C%7C%22Kh%3D%2BJ%3DNh%2FJ3%5BF*2%7C%40d%3BKrz0&input=Hello+world.&test_suite_input=abcdefga%0AHello+world.%0Alorem+ipsum%0Aa.a.a.x.x.x.a.a.a&debug=0)
### Explanation
I hid this away by default since it's way too long.
```
<ul type="disc"><li>Initialize <code>K</code> to <code>"/\"</code>.</li><li>Lowercase (<code>r</code>&hellip;<code>0</code>) the input (<code>z</code>).</li><li>For each (<code>m</code>) character <code>d</code> in the lowercase input:</li><ul type="disc"><li>Find the index (<code>x</code>) of the character (<code>d</code>) in the alphabet (<code>G</code>). This results in a number 0-25 for the letters and -1 for anything else. Save the index to <code>J</code>.</li><li>Add one (<code>h</code>). This results in a positive number for the letters and 0 for anything else.</li><li>If the result was nonzero (<code>?</code>):</li><ul type="disc"><li>Int-divide (<code>/</code>) <code>J</code> by <code>3</code> and increment (<code>h</code>) and save (<code>=</code>) the result to <code>N</code>.</li><li>Increment (<code>=+</code>) <code>J</code> by that amount.</li><li>Add one (<code>h</code>). This yields the height of the house excluding the roof.</li><li>For each (<code>m</code>) number <code>k</code> from 0 to result-1:</li><ul type="disc"><li>Take <code>" "</code> (<code>\ </code>) if (<code>?</code>) the number (<code>k</code>) is not equal to (<code>n</code>) <code>J</code>, otherwise take <code>"_"</code> (<code>\_</code>).</li><li>Int-divide (<code>/</code>) the number (<code>k</code>) by <code>4</code>, double (<code>y</code>) and add one (<code>h</code>).</li><li>Multiply the string by the number (<code>*</code>).</li><li>Take <code>"||"</code> if (<code>?</code>) the number (<code>k</code>) is not divisible by 4 (<code>%</code>&hellip;<code>4</code>), otherwise take the string in <code>K</code>.</li><li>Join (<code>j</code>) that string by the previous one. This puts the previous string in the middle.</li></ul><li>Prepend (<code>+</code>) a <code>"_"</code> (<code>\_</code>) to the resulting list to add the roof.</li><li>For each line <code>k</code> in the list:</li><ul type="disc"><li>Take <code>N</code>, double (<code>y</code>) and add one (<code>h</code>).</li><li>Pad (<code>.[</code>) the line (<code>k</code>) to that length with spaces (<code>\ </code>).</li></ul><li>We now have the rows for this one house. Reverse (<code>_</code>) and transpose (<code>C</code>) the result to get the reversed columns.</li></ul><li>If the result was zero (all the way up there):</li><ul type="disc"><li>Take the intersection (<code>@</code>) of the character (<code>d</code>) and <code>" "</code> (<code>;</code>). This yields an empty string for periods and a space for itself.</li><li>Logical OR (<code>|</code>) that with the string in <code>K</code>. This yields that string for periods and a space for itself.</li><li>Repeat that string (<code>*</code>) <code>2</code> times and cast to array (<code>[F</code>). This yields the (reversed) columns for spaces and periods.</li></ul></ul><li>Concatenate (<code>s</code>) the resulting lists. This yields the total reversed columns for the output.</li><li>Transpose, padding with spaces (<code>.t</code>), reverse (<code>_</code>) and join by newline (<code>j</code>). Implicitly print the output.</li></ul>
```
[Answer]
# Perl, ~~147~~ 146 bytes
Includes +1 for `-p`
Run with input on STDIN, e.g.
```
citysky.pl <<< " abcdefgxyz."
```
`citysky.pl`:
```
#!/usr/bin/perl -p
s%.%@{[map chr~-ord(lc$&)*4/3-4*(abs||-9),-9..9]}%g;y/M\xa248
A|-\xc6\0-\xff/MA||
A}-\xc6A/d,$a=(lc$a).$_ for($_)x36;*_=a;s/\x9f.*?\K\x9f/\xa3/g;y%A\xc6\x9f-\xa3\x0b-\xff%__/|||\\ %
```
Works as shown, but replace the `\xhh` escapes by their literal value to get the claimed score. You can do that using this commandline:
```
perl -0pi -e 's/\\x(..)/chr hex $1/eg;s/\n$//' citysky.pl
```
I haven't really explored any other approaches, so this may be very beatable...
[Answer]
# Haskell, 289 bytes
```
c?l=c++l++c
c%s=("|"?(drop 2(r s)>>c)):s
g 46=["/\\"?""]
g 32=["  "]
g x="_"%h(mod x 32)
h 1=["/ \\"," _ "]
h x=(" "%h(x-1))!x
v!x|mod x 3/=1=v|z<-'/':r v++"\\"=z:map(" "?)v
r v=v!!0>>" "
f t|l<-map(g.fromEnum)t,m<-maximum(map length l)-1=unlines[l>>= \x->(x++cycle[r x])!!i|i<-[m,m-1..0]]
```
[Answer]
## Ruby, 245
```
->s{a=['']*36
w=' '
s.chars{|c|a[u=0]+=c<?!?w*2:c<?/?"/\\"*2:(h=c.upcase.ord-64
1.upto(1+h+=(h-1)/3){|t|u=[u,l=1+2*((f=h-t)/4)].max
a[t]+=w*(a[0].size-a[t].size)+(f<-1?w:f<0??_:(f%4<1?[?/,?\\]:[?|]*2)*(w*l)).center(u+2)}
"|#{?_*u}|")}
a.reverse}
```
You allow as many extra newlines as you want, so I'm taking liberty with that. Aside from that, the process is as follows:
1. Initialize an output array `a`.
2. For each char:
	1. if it's ' ', add  to `a[0]`
	2. if it's '.', add `/\/\` to `a[0]`
	3. otherwise:
		1. calculate the height (`c.upcase.ord + (c.upcase.ord-1)/3`)
		2. for each row in `a`:
			1. pad the row with whitespace. `a[t]+=w*(a[0].size-a[t].size)`
			2. if we're one above `h`, center a `_`
			3. else if we're above height, center a
			4. else if we're below height, center `| |` or `/ \` of the proper width (`1+2*((h-t)/4`), depending on if `h-t%4==0`
			5. add `"|___|"` of the right width to `a[0]`
3. return `a.reverse`
I bet I can get it smaller if I work out the math to avoid `reverse`
[Answer]
# PHP, 297 bytes
```
foreach(str_split($argv[1])as$c)for($j=0,$h=ord($c)-64,$g=$h+$f=ceil($h/3),$w=$v=$h<0?$h<-18?2:4:2*$f+1;$j<36;$j++,$g--,$v-=$h>0&&$v>1?($g%4||!$j)?0*$n="|$s|":2+0*$n="/$s\\":$v+0*$n=['','_','',0,'/\/\\'][$v],$o[$j].=str_pad($n,$w,' ',2))$s=str_repeat($j?' ':'_',$v-2);krsort($o);echo join($o,'
');
```
A more readable version:
```
foreach (str_split($argv[1]) as $character) {
    for (
        $line = 0,
        $buildingHeight = ord($character) - 64,
        $floorsLeft = $buildingHeight + $supportFloors = ceil($buildingHeight / 3),
        $buildingWidth = $widthOnThisFloor = $buildingHeight < 0
            ? $buildingHeight < -18
                ? 2
                : 4
            : 2 * $supportFloors + 1;
        $line < 36;
        // The body of the for-loop is executed between these statements
        $line++,
        $floorsLeft--,
        $widthOnThisFloor -= $buildingHeight > 0 && $widthOnThisFloor > 1
            ? ($floorsLeft % 4 || !$line)
                ? 0 * $floorString = "|$middleSpacing|"
                : 2 + 0 * $floorString = "/$middleSpacing\\"
            : $widthOnThisFloor + 0 * $floorString = ['', '_', '', 0, '/\/\\'][$widthOnThisFloor],
        $outputArray[$line] .= str_pad($floorString, $buildingWidth, ' ', 2)
    ) {
        $middleSpacing = str_repeat($line ? ' ' : '_', $widthOnThisFloor - 2);
    }
}
krsort($outputArray);
echo join($outputArray, '
');
```
]