[Question]
  [
Given an input of a "hotel" in ASCII art with a single room marked, output the
room number according to certain rules.
Here's an example of an ASCII hotel:
```
               ##
               ##
#####          ##
#####  ######  ##
#####  ######  ##
#####  ######  ##
```
Here are a few more things about the ASCII hotels:
* Each "building" is represented by a rectangle of `#` characters, where each
`#` represents a "room".
* The above hotel consists of three buildings. Each building is separated by
two columns of spaces, and the lowest "floor" will always be on the last
line.
* Each building will always have anywhere from 1-9 "floors" (rows) and 1-9
"rooms" on each floor. There will also always be 1-9 buildings.
* Rooms are numbered as follows: `[building #][floor #][room on floor #]`. For
example, let's mark a few rooms in the above drawing:
```
               ##
               ##
#####          ##
#####  ####$#  ##
##%##  ######  ##
#####  ######  #@
```
The room marked with the `%` is room 123 (building 1, floor 2, 3rd room on
floor). Similarly, the room marked with the `$` is room 235, and the `@` is
room 312.
* Buildings, floors, and "nth room on floor"s are always 1-indexed.
The input will consist of an ASCII hotel with a single room replaced with an
asterisk (`*`). This is the room for which you must output the room number. The
input must be taken as a single string, but you may use commas as line
separators instead of newlines (in case your language of choice cannot take
multiline input or if it's shorter to take single-line input). You may
optionally require a trailing comma/newline. You may also pad lines with
trailing spaces to make the input a complete rectangle.
Since this is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), the shortest code in bytes wins.
Test cases (contained within a single code block to conserve vertical space):
```
Input:
*
Output: 111
Input:
#  #  *  #  #
Output: 311
Input:
#####
#####
####*
#####
#####
Output: 135
Input:
         #####
         #####           ######
         #####           ######
#  #  #  #####  #  #  #  ######  *
Output: 911
Input:
#
#  #
#  #  ##
#  #  ##  ###
#  #  ##  ###  #####
#  #  ##  ###  ##*##  ########
#  #  ##  ###  #####  ########
Output: 523
Input:
           #
           *
           #
           #
           #
           #
           #
           #
#########  #  #
Output: 281
Input:
                        ########*
                        #########
                        #########
                        #########
                        #########
                        #########
                        #########
                        #########
#  #  #  #  #  #  #  #  #########
Output: 999
```
  
[Answer]
## CJam, ~~34~~ 31 bytes
```
qN/W%zSf-La%{_{s'*&}#_)@@=}3*;\
```
This requires the input to be padded to a rectangle with spaces.
[Try it online!](http://cjam.tryitonline.net/#code=cU4vVyV6U2YtTGEle197cycqJn0jXylAQD19Myo7XA&input=ICAgICAgICAgIyMjIyMgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAjIyMjIyAgICAgICAgICAgIyMjIyMjICAgCiAgICAgICAgICMjIyMjICAgICAgICAgICAjIyMjIyMgICAKIyAgIyAgIyAgIyMjIyMgICMgICMgICMgICMjIyMjIyAgKg) Alternatively, [run all test cases.](http://cjam.tryitonline.net/#code=cU4yKi97Ti9feixme1NlXXN9Tio6UTsKClFOL1clelNmLUxhJXtfe3MnKiZ9I18pQEA9fTMqO1wKCl1vTm99Lw&input=KgoKIyAgIyAgKiAgIyAgIwoKIyMjIyMKIyMjIyMKIyMjIyoKIyMjIyMKIyMjIyMKCiAgICAgICAgICMjIyMjCiAgICAgICAgICMjIyMjICAgICAgICAgICAjIyMjIyMKICAgICAgICAgIyMjIyMgICAgICAgICAgICMjIyMjIwojICAjICAjICAjIyMjIyAgIyAgIyAgIyAgIyMjIyMjICAqCgojCiMgICMKIyAgIyAgIyMKIyAgIyAgIyMgICMjIwojICAjICAjIyAgIyMjICAjIyMjIwojICAjICAjIyAgIyMjICAjIyojIyAgIyMjIyMjIyMKIyAgIyAgIyMgICMjIyAgIyMjIyMgICMjIyMjIyMjCgogICAgICAgICAgICMKICAgICAgICAgICAqCiAgICAgICAgICAgIwogICAgICAgICAgICMKICAgICAgICAgICAjCiAgICAgICAgICAgIwogICAgICAgICAgICMKICAgICAgICAgICAjCiMjIyMjIyMjIyAgIyAgIwoKICAgICAgICAgICAgICAgICAgICAgICAgIyMjIyMjIyMqCiAgICAgICAgICAgICAgICAgICAgICAgICMjIyMjIyMjIwogICAgICAgICAgICAgICAgICAgICAgICAjIyMjIyMjIyMKICAgICAgICAgICAgICAgICAgICAgICAgIyMjIyMjIyMjCiAgICAgICAgICAgICAgICAgICAgICAgICMjIyMjIyMjIwogICAgICAgICAgICAgICAgICAgICAgICAjIyMjIyMjIyMKICAgICAgICAgICAgICAgICAgICAgICAgIyMjIyMjIyMjCiAgICAgICAgICAgICAgICAgICAgICAgICMjIyMjIyMjIwojICAjICAjICAjICAjICAjICAjICAjICAjIyMjIyMjIyM)
### Explanation
```
qN/      e# Read input and split into lines.
W%z      e# Rotate 90° counter-clockwise.
Sf-      e# Remove all spaces from the rows.
La%      e# Split into buildings. We've now got a 3D array of rooms, where the first
         e# dimension is the building, the second the room number and the third is the
         e# the floor number.
{        e# Run this block three times. At each stage it will find the index of the "*"
         e# along the current dimension and leave the element at that index on the stack
         e# for the next round...
  _      e#   Duplicate the current array.
  {      e#   Find the index of the first element where this block yields something
         e#   truthy...
    s    e#     Flatten into a single string.
    '*&  e#     Set intersection with "*".
  }#
  _)     e#   Duplicate the index and increment it, because the results should be 1-based.
  @@=    e#   Pull up the array and the other copy of the index and select the
         e#   corresponding element.
}3*
;\       e# We've now got the building, room and floor index on the stack, as well as the
         e# "*" character itself. We discard the character and swap the room and the floor
         e# floor number. When the three indices are printed back-to-back at the end of
         e# the program, that will yield the desired result.
```
[Answer]
# Pyth, 34 bytes
```
LxKh/#\*b\*jkhM[//<hJ_.zyJd2xJKycK
```
[Demonstration](https://pyth.herokuapp.com/?code=LxKh%2F%23%5C%2ab%5C%2ajkhM%5B%2F%2F%3ChJ_.zyJd2xJKycK&input=%23%0A%23++%23%0A%23++%23++%23%23%0A%23++%23++%23%23++%23%23%23%0A%23++%23++%23%23++%23%23%23++%23%23%23%23%23%0A%23++%23++%23%23++%23%23%23++%23%23%2a%23%23++%23%23%23%23%23%23%23%23%0A%23++%23++%23%23++%23%23%23++%23%23%23%23%23++%23%23%23%23%23%23%23%23&debug=0)
This uses a golfing trick I've never used before: Assigning to a variable (`K`) inside a function (`y`) to save a partial result from that function.
### Explanation:
```
LxKh/#\*b\*jkhM[//<hJ_.zyJd2xJKycK
L                                     Define y(b):      (b is a list of strigs)
    /#\*b                             Filter b for strings containing '*'
   h                                  Take the first such string
  K                                   Store it in K
 x       \*                           And return the index of '*' in that string.
                      .z              Take the input as a list of strings
                     _                Reverse it (bottom to top)
                    J                 Store in J
                   h                  Take the bottommost row
                        yJ            Find y(J). This is the index in whichever
                                      row of J has the * of the *. Also store
                                      that row in K.
                  <                   Slice J up to that index.
                 /        d           Count the number of spaces
                /          2          Divide by 2. This is the building number.
                            xJK       Take the index in J of K. This is the floor.
                                cK    Chop K on whitespace.
                               y      Find the index in whatever element of K has
                                      the * of the *. This is the room number.
                                      This also overwrites K, but we don't care.
               [                      Gather the above into a list.
             hM                       Convert 0-indexing to 1-indexing.
           jk                         Concatenate. Print implicitly.
```
[Answer]
# JavaScript (ES6), ~~142~~ 136 bytes
```
h=>h.split`
`.reverse(r=0).map((t,i,l)=>r?0:(f=i+1,b=1,l[o=0].slice(0,r=t.indexOf`*`+1).replace(/  /g,(_,s)=>o=++b&&s+2),r-=o))&&[b]+f+r
```
*6 bytes saved thanks to [@nderscore](https://codegolf.stackexchange.com/users/20160/nderscore)!*
## Explanation
```
h=>
  h.split`
`                            // get each line of the input string
  .reverse(                  // reverse the lines to make getting the ground floor easy
    r=0)                     // initialise r to 0
  .map((t,i,l)=>             // for each line of the reversed input string
    r?0:(                    // if the marked room has not been found yet:
      f=i+1,                 // f = floor number
      b=1,                   // b = building number, default to 1
      l[o=0].slice(0,        // get the substring of 0 to the marked room, default o to 0
        r=t.indexOf`*`+1)    // r = absolute index of room + 1 (or 0 if not found)
      .replace(/  /g,(_,s)=> // count the spaces between buildings
        o=++b&&s+2),         // increment b, o = index of marked room's building
      r-=o                   // make r relative to the room's building
    )
  )
  &&[b]+f+r                  // output the result ([b] casts b to a string)
```
## Test
```
var solution = h=>h.split`
`.reverse(r=0).map((t,i,l)=>r?0:(f=i+1,b=1,l[o=0].slice(0,r=t.indexOf`*`+1).replace(/  /g,(_,s)=>o=++b&&s+2),r-=o))&&[b]+f+r
```
```
<textarea id="input" rows="8" cols="60">#
#  #
#  #  ##
#  #  ##  ###
#  #  ##  ###  #####
#  #  ##  ###  ##*##  ########
#  #  ##  ###  #####  ########</textarea><br />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>
```
[Answer]
# awk, 70
```
!i{i=index($0,"*")}i{$0=substr($0,0,i);f++}END{print NF f length($NF)}
```
Example:
```
Input:
#
#  #
#  #  ##
#  #  ##  ###
#  #  ##  ###  #####
#  #  ##  ###  ##*##  ########
#  #  ##  ###  #####  ########
While no * was found, do nothing.
#
#  #
#  #  ##
#  #  ##  ###
#  #  ##  ###  #####
A * is found in column 14. From now on, truncate and increment the floor counter.
#  #  ##  ###  ##*    f=1
#  #  ##  ###  ###    f=2
Awk automatically splits $0 into space separated fields, counted by builtin NR.
In the end, NR and f hold hotel and floor number.
The room number is the length of the last hotel.
```
[Answer]
# C, 131 130 119 113 bytes
```
b,f,i,j=111;main(c){for(;c=~getchar();)c&32?f+=10,b=i=0:++i<j?c%3?f=j,j=i:c&2?b+=50-b%50:++b:0;printf("%d",b+f);}
```
Takes input on stdin; input must *not* have a terminating newline. Assumes 2's complement.
Ungolfed:
```
// Declare variables (default type is int) and initialize, by default to 0:
b,    // Building number (multiplied by 100, 0-based) + room number (0-based)
f,    // Floor (111-based, multiplied by 10)
i,    // Current column of input character within line (1-based)
j = 111; // Column of asterisk character once found (1-based), 111 before then
main (c)    // Declare main function and variable c to hold input character
{
  for (;    // Loop on input
    c = ~getchar();  // Read a character into c, bitwise inverted to break
                     // EOF (numeric value -1). This means that following 
                     // operations (on the ASCII value of the input) are 
                     // also inverted.
    )
    c & 32 ?              // Newline?
      f += 10, b = i = 0 :  // Increment floor; reset building, room, column
      ++i < j ?             // Increment column; before asterisk, or asterisk not yet found?
        c % 3 ?               // Asterisk character?
          f = j, j = i :        // Reset floor and record column
          c & 2 ?               // Space character?
            b += 50 - b % 50 :    // Increment building and reset room
            ++b :                 // Otherwise, # character; increment room
        0;                    // After asterisk; do nothing
  printf("%d", b + f);  // Write out results
}
```
[Answer]
# [Stackgoat](https://github.com/vihanb/Stackgoat), 73 bytes [non-competing]
Stackgoat is a stack-based language that has nothing to do with goats.
```
y'#ZGDYZG'*iVXsV@"\\*"ZGN2/1+y'#ZG' ZG'q:Nq'*i-yXsq'*i@"[#*]+"M0M1-@'*i1+
```
It's a fairly new language so let me know if they're any problems with it. I gave myself quite a headache figuring this out so this is about as much as I'm golfing this.
### Explanation
This program has 3 parts for each 3 digits of the room number
```
y'#ZG    // Remove all # from input
D        // Duplicate
YZG      // Remove all spaces
'*i      // Index of *
V        // Reverse stack
Xs       // Split on spaces
V@       // Unreverse, item at *'s index
"\\*"ZG  // Remove all *s
N        // Get length
2/1+     // Divide by 2, add 1
y'#ZG    // Remove all #
' ZG     // Remove all spaces
'q:      // Store in q
N        // Get length
q'*i     // *'s index in q
-        // Subtracted from length
yXs      // Split on newlines
q'*i     // Get index of * in q
@        // Get indexed-th line
"[#*]+"M // Match all buildings
0M       // Get *'s building no.
1-       // Subtract one
@        // nth building at right line
'*i      // *'s index
1+       // Added to one
```
[Answer]
# Ruby, 103
```
->n{r=x=b=0
n.lines{|s|(t=s=~/\*/)&&(x=t;r=($`.reverse+' ')=~/ /)
r+=10;b=s[0..x].count" "}
b*50+r+101}
```
Ungolfed in test program
```
g=->n{
  r=x=b=0
  n.lines{|s|                  #for each line in n
    (t=s=~/\*/)&&              #if the line contains an asterisk
      (x=t                     #record its position in x. $` is a special variable containing the part of the string to the left of the last match made.
      r=($`.reverse+' ')=~/ /) #reverse $` and search for the index of the first space to find room number (before the search a space is appended in case it is 1st building.)
    r+=10                      #increment r by 10 for the floor number (obviously this will have been reset to the row ith the asterisk by the previous line)
    b=s[0..x].count" "}        #count the number of spaces left of x in the current row to find building number (loop will exit with calc from bottom row, which is the correct one.) 
b*50+r+101}                    #multiply number of spaces by 50 to get 1st digit, add r for 2nd and 3rd digit. Then add 101 to correct 1st and 3rd digits from 0-indexed to 1-indexed.
puts g["
*"]
puts g["
#  #  *  #  #"]
puts g["
#####
#####
####*
#####
#####"]
puts g["
         #####
         #####           ######
         #####           ######
#  #  #  #####  #  #  #  ######  *"]
puts g["
#
#  #
#  #  ##
#  #  ##  ###
#  #  ##  ###  #####
#  #  ##  ###  ##*##  ########
#  #  ##  ###  #####  ########"]
puts g["
           #
           *
           #
           #
           #
           #
           #
           #
#########  #  #"]
puts g["
                        ########*
                        #########
                        #########
                        #########
                        #########
                        #########
                        #########
                        #########
#  #  #  #  #  #  #  #  #########"]
```
[Answer]
# JavaScript (ES6), 121
```
x=>x.split`
`.reverse().map((r,f,h,a=r.indexOf`*`)=>x=~a?(h=h[0].slice(0,a).split`  `).length+[f+1]+-~h.pop().length:x)|x
```
**Less golfed and explained**
```
H=x=>x.split`\n` // split in lines
  .reverse() // reverse, so we can scan bottom up
  .map( (r,f,h) => // exectute for each line
         // r is the current row
         // f in the row index, so that f+1 is the floor number
         // h is the reversed array, h[0] is the bottom floor
       ~(a=r.indexOf`*`) // a is the position of '*' in the line, if found - else 0
       && ( // if a >= 0
         h = h[0]        // bottom floor line 
             .slice(0,a) // ... truncated at position of '*'
             .split`  `, // ... and splitted at '  ', as an array
         x = h.length  // the array len is the building number
             + [f+1]   // floor number, using [] to force string concatenation
             + -~ h.pop().length // the length of the last array element is the number 
                                 // of chars in the block before '*'
                                 // increment by 1 to get the room number
      )
  )
  && x // return the found value
```
**TEST**
```
H=x=>x.split`
`.reverse().map((r,f,h,a=r.indexOf`*`)=>x=~a?(h=h[0].slice(0,a).split`  `).length+[f+1]+-~h.pop().length:x)|x
// test
console.log=x=>O.textContent+=x+'\n';
;[['*',111],['#  #  *  #  #',311],
[`#####
#####
####*
#####
#####`,135],
[`         #####
         #####           ######
         #####           ######
#  #  #  #####  #  #  #  ######  *`,911],
[`#
#  #
#  #  ##
#  #  ##  ###
#  #  ##  ###  #####
#  #  ##  ###  ##*##  ########
#  #  ##  ###  #####  ########`,523],
[`           #
           *
           #
           #
           #
           #
           #
           #
#########  #  #`,281],
[`                        ########*
                        #########
                        #########
                        #########
                        #########
                        #########
                        #########
                        #########
#  #  #  #  #  #  #  #  #########`,999]]  
.forEach(t=>{
  var i=t[0],k=t[1],r=H(i)
  console.log(i+'\n' + (k!=r?'Error '+r+' expected '+k:'Ok '+r)+'\n')
})
```
```
<pre id=O></pre>
```
[Answer]
## Python 2.7, ~~153~~ 168 characters
I liked this challenge! If a Python list is ok as input (see testsuite for examples), this solution works.
*Edit 2016-01-05:* added one line (10 characters) to split the string in multiline.
Short explanation: 
* `t` is the row in which the room is located (counted from the top-row as array index = 0);
* `i` is the index of the room in its row;
* the building is calculated as the number of double white spaces in the bottom row until `i`;
* floor is the number of row minus `t`;
* room is the index of the first double whitespace in the reversed string from `i` until the beginning of the floor with the room, appended by a whitespace to cover for the case that the room is in the first building.
Code:
```
def r(l):
 l=h.split(",")
 a,w,s="*","  ",str
 t=l.index(filter(lambda c:a in c,l)[0])
 i=l[t].find(a)
 return s(l[-1][:i].count(w)+1)+s(len(l)-t)+s((l[t][i::-1]+w).find(w))
```
Testsuite:
```
cases = [
         (["*"], 111),
         (["#  #  *  #  #"], 311),
         (["#####","#####","####*","#####","#####"], 135),
         (["         #####","         #####           ######","         #####           ######","#  #  #  #####  #  #  #  ######  *"], 911),
         (["#","#  #","#  #  ##","#  #  ##  ###","#  #  ##  ###  #####","#  #  ##  ###  ##*##  ########","#  #  ##  ###  #####  ########"], 523),
         (["           #","           *","           #","           #","           #","           #","           #","           #","#########  #  #"], 281),
         (["                        ########*","                        #########","                        #########","                        #########","                        #########","                        #########","                        #########","                        #########","#  #  #  #  #  #  #  #  #########"], 999)
        ]
for idx,(hotel,roomnr) in enumerate(cases):
    output=r(hotel)
    if str(output)==str(roomnr):
        result="SUCCESS"
    else:
        result="FAILURE!!!"
    print "Case {} gives output: {}. Correct output is: {}. Result: {}".format(idx,output,roomnr,result)
```
[Answer]
# [Snails](https://github.com/feresum/pma), 32 bytes
```
A
\*{l\#,|r,9d.,{|=~r,9{|l.,\ \#
```
[Answer]
# C, ~~142~~ ~~138~~ 137 bytes
```
#include <stdio.h>
f,b,x,p=110;main(c){while(~(c=getchar()))c<11?f+=c,b=x=0:x++<p?++b,c&2?c&8?f=p,p=x:0:(b+=50-b%50):0;printf("%d",b+f);}
```
(~~123~~ ~~119~~ 118 bytes + 19 for `#include` line)
I stole the value merging idea from ecatmur, but I've merged them in quite a different way (~~saves 8 bytes in the end~~). This also makes the same assumption that `EOF == -1`.
The input is taken from stdin, and must not have whitespace or newlines after the last building on the last line, so an example input would be:
```
printf "##\n##       #\n##  ##*  #\n##  ###  #" | ./hotel
# or for better visualisation:
printf "##\n##       #\n##  ##*  #\n##  ###  #" | tee /dev/fd/2 | ./hotel;echo ""
```
Breakdown:
```
// Globals initialise to 0
f,     // floor number * 10 + shift
b,     // building number * 100 + room number
x,     // current column
p=110; // will store column of * (must start >= 11*9-2, and 110 will be used later)
main(c){
    while(~(c=getchar()))              // For each character until EOF
        c<11                           //  Is \n? (10)
            ?f+=c,                     //   Add 10 to floor number
             b=x=0                     //   Reset building, room, column
            :x++<p                     //  Else, is column <= *?
                  ?++b,                //   Add to room number
                   c&2                 //   Is # or *?
                      ?c&8             //   If *:
                          ?f=p,p=x:0   //    Set floor to 110, set p to column
                      :(b+=50-b%50)    //   If ' ': go to next building
                  :0;
    printf("%d",b+f);                  // Result is building+room+floor+shift
}
```
[Answer]
## Haskell, ~~128~~ 125 bytes
```
l=length
f h|b<-snd$break(elem '*')$lines h,q<-fst(span(<'*')$b!!0)++"*"=l(last$words$q)+10*l b+l(words$take(l q)$last b)*100
```
Usage example: `f "# # * # #"` -> `311`.
How it works:
```
b<-snd$break(elem '*')$lines h      -- split the input into a list of lines
                                    -- and assign b to the lines starting with
                                    -- the one that includes * up to the end,
                                    -- i.e. drop leading lines without the *
q<-fst(span(<'*')$b!!0)++"*"        -- assign q to the line with the *, but strip
                                    -- off all chars after the *
l(last$words$q)                     -- the room on floor number is the length of
                                    -- the last word of q
10*l b                              -- the floor number is 10 times the length of b
l(words$take(l q)$last b)*100       -- the hotel number is 100 times the number of
                                    -- words in the last line cut down to the
                                    -- length of q
                                    -- add for final room number
```
[Answer]
## Lua, 165 Bytes
```
l={}i=1while(l[i-1]~="")do l[i]=io.read()o=l[i]:find"%*"x=o or x y=o and i or y i=i+1 end print(#l[i-2]:sub(1,x):gsub("%S+%s*","#")*100+(i-y-1)*10+#l[y]:match"#-%*")
```
**Ungolfed**
```
l={}
i=1
while(l[i-1]~="")do
    l[i]=io.read()
    o=l[i]:find"%*" --find "*", and record:
    x=o or x        --position and
    y=o and i or y  --current floor
    i=i+1
end
print(#l[i-2]:sub(1,x):gsub("%S+%s*","#")*100 --[[Take last string of list, and then
                                                  take the substring up until the 
                                                  asterisk. Substitute any substrings
                                                  that include nonspace characters 
                                                  (%S+) followed by a minimum of 0 space 
                                                  characters (%s*) with one character
                                                  (in this code snippet I chose # for no 
                                                  particular reason.) Then take the length 
                                                  of this string, with the # operator. 
                                                  The %S+%s* regex and gsub do the bulk 
                                                  of the magic.
                                                ]]
      +(i-y-1)*10                             --[[Total number of lines minus '*' floor 
                                                  minus one.
                                                ]]
      +#l[y]:match"#-%*")                     --[[Find the substring on the asterisk floor
                                                  with '#' symbols preceding an asterisk.
                                                ]]
```
[Answer]
## CoffeeScript, 110 bytes & JavaScript, 121 bytes
```
(s)->s.split('\n').reverse().map((f,g)->f.split('  ').map((h,i)->r=h.indexOf('*');s=''+i+g+r if r>-1));111+1*s
```
## Readable
```
(s)->
    s.split '\n' 
        .reverse()
        .map (f,fi)->
            f.split('  ')
                .map (h,hi)->
                    ri = h.indexOf('*')
                    s = ''+hi+fi+ri if ri>-1
    111+1*s
```
Basically same thing in Javascript:
```
(s)=>{s.split('\n').reverse().map((f,g)=>f.split('  ').map((h,i)=>{r=h.indexOf('*');r>-1?s=''+i+g+r:''}));return 111+1*s}
```
[Answer]
## Java, 231 Bytes
```
String a(String a){String[]b=a.split("\n");int i=0,c=b.length,m;String x,k=" ";for(;i<c;i++){x=b[c-1].substring(0,b[i].indexOf("*")+1);m=x.length();a=m>0?""+(m-x.replace(k+k,k).length()+1)+(c-i)+(m-x.lastIndexOf(k)-1):a;}return a;}
```
De-Golfed
```
 String a(String a) {
     String[] b = a.split("\n");                                // Split the input into floor lines
     int i = 0, c = b.length, m;                                // i=floor line counter c= number of floor lines
     String x, k = " ";
     for (; i < c; i++) {                                       // Loop through floor lines
        x = b[c - 1].substring(0, b[i].indexOf("*") + 1);       // x = part of bottom floor line up to '*' position in current line (Empty string when no '*')
        m = x.length();                                         // m = length of floor line part
        a = m > 0 ? "" + (m - x.replace(k + k, k).length() + 1) // if m>0 ('*' is on this line) set a=building no+floor no+room no.   building no calculated by replacing double space in x with single space and compare length to x (+1) 
              + (c - i)                                         // floor number is total floor lines (c) - floor line loop counter (i)
              + (m - x.lastIndexOf(k) - 1) : a;                 // room number is m ('*' position in x) - position of last space in x (-1)
     }
     return a;                                                  // return the result at the end.
  }
```
[Answer]
# Powershell, 154 bytes
```
param($s)filter s{$s|sls $_ -a|% M*|% Le*}(($s-split'
')[-1]|% s*g 0('(?m)^.*\*'|s)|sls '^|  '-a|% M*).Count,('(?ms)(?<=\*.*)$'|s).Count,('#*\*'|s)-join''
```
Less golfed test script:
```
$f = {
param($s)
filter s{
    $s|sls $_ -AllMatches|% Matches|% Length
}                                   # select an array of lengths of all matches of the string $s by pattern $_
$hpos='(?m)^.*\*'|s                 # horizontal position of the room in the source string
$basement=($s-split"`n")[-1]        # basement floor string
$building=($basement|% substring 0 $hpos|sls '^|  ' -AllMatches|% Matches).Count
                                    # truncate the basement to the position of the room
                                    # and count all double spaces or a 'start of string'
$floor=('(?ms)(?<=\*.*)$'|s).Count  # count all 'end of line' after the room
$room='#*\*'|s                      # count all #, preceding the room, and room itself
$building,$floor,$room-join''
}
@(
,(@"
*
"@, 111)
,(@"
#  #  *  #  #
"@,311)
,(@"
#####
#####
####*
#####
#####
"@, 135)
,(@"
        #####
        #####           ######
        #####           ######
#  #  #  #####  #  #  #  ######  *
"@, 911)
,(@"
#
#  #
#  #  ##
#  #  ##  ###
#  #  ##  ###  #####
#  #  ##  ###  ##*##  ########
#  #  ##  ###  #####  ########
"@, 523)
,(@"
        #
        *
        #
        #
        #
        #
        #
        #
#########  #  #
"@, 281)
,(@"
                        ########*
                        #########
                        #########
                        #########
                        #########
                        #########
                        #########
                        #########
#  #  #  #  #  #  #  #  #########
"@, 999)
) | % {
    $n,$expected = $_
    $result = &$f $n
    "$($result-eq$expected): $result"
}
```
Output:
```
True: 111
True: 311
True: 135
True: 911
True: 523
True: 281
True: 999
```
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E/wiki/Commands), 34 [bytes](https://github.com/Adriandmen/05AB1E/wiki/Codepage)
```
|€SζJðмõ¡εεR'*k>]DOZ©k>;ò®«sĀ€ƶ˜à«
```
Zip with string-lists is currently bugged. `€SζJ` could have been just `ζ` in the old Python legacy version of 05AB1E, but for some reason doesn't work in the Elixir rewrite version anymore.
[Try it online](https://tio.run/##yy9OTMpM/f@/5lHTmuBz27wOb7iw5/DWQwvPbT23NUhdK9su1sU/6tDKbDvrw5sOrTu0uvhIA1DlsW2n5xxecGj1//8KCgrKyspcysgUiIAwtUAEAA) or [verify all test cases](https://tio.run/##yy9OTMpM/V9W@f9R05rgc9u8Dm@4sOfw1kMLz209tzVIXSvbrrbWxT/q0MpsO@vDmw6tO7S6@EgDUOmxbafnHF5waPV/nf/R0UpaSrE6CtFKygoKQKQFJpWhQiCgpINCa6HxoUoVYAAmhyqgoIDKJ04FxEnKcBWofJBroe6EqkVoQWaClaPzEQ7FENaCy@LWh6QA1fsQVyBxtVC5ytTlwlyhjBxtCjgATC2ak7CqUR7GalBSEkaqQo5ThHokBlLyUtYCc2JjAQ).
**Explanation:**
```
|                    # Take the input split by newlines
                     #  i.e. "   ###\n#  ###\n#  ###  ##\n#  ##*  ##"
                     #   → ["   ###","#  ###","#  ###  ##","#  ##*  ##"]
 €S                  # Convert each to a list of characters
   ζ                 # Zip, swapping rows and column
    J                # Join them together to a string again
                     #  → [" ###","    ","    ","####","####","###*","    ","    ","  ##","  ##"]
     ðм              # Remove all spaces
                     #  → ["###","","","####","####","###*","","","##","##"]
       õ¡            # Split on empty strings
                     #  → [["###"],[],["####","####","###*"],[],["##","##"]]
ε                    # Map each building to:
 ε                   #  Map each column of the building to:
  R                  #   Reverse the column
   '*k              '#   Get the 0-indexed index of "*"
      >              #   Increase it by 1 to make it 1-indexed
]                    # Close both maps
                     #  → [[0],[],[0,0,1],[],[0,0]]
 D                   # Duplicate the resulting list
  O                  # Sum each building
                     #  → [0,0,1,0,0]
   Z                 # Get the max (without popping)
                     #  → 1
    ©                # Store this max in the register (without popping)
     k>              # Get the index (+ 1) of this max in the sum-list
                     #  → 3
       ;             # Halve it
                     #  → 1.5
        ò            # Round it up to the nearest integer (bankers rounding)
                     #  → 2
         ®           # Retrieve the value from the register again
          «          # Merge the two digits together
                     #  → 21
           s         # Swap so the duplicate list is at the top again
            Ā        # Trutify (0 remains 0, every other integer becomes 1)
                     #  → [[0],[],[0,0,1],[],[0,0]]
             €       # For each building:
              ƶ      #  Multiply the integer with the 1-indexed index
                     #  → [[0],[],[0,0,3],[],[0,0]]
               ˜     # Flatten the list
                     #  → [0,0,0,3,0,0]
                à    # Pop the list, and get the max
                     #  → 3
                 «   # Merge it with the other two digits (and output implicitly)
                     #  → 213
```
[Answer]
# [Dart](https://www.dartlang.org/), 165 bytes
```
F(List s)=>s.indexWhere((a)=>a.contains('*'));f(String s){var b=s.split('\n'),v=F(b),c=b[v].split('  '),w=F(c),x=c[w].indexOf('*')+1;return '${w+1}${b.length-v}$x';}
```
[Try it online!](https://tio.run/##hZFNa4NAEIbv/orFCPsRI6jJocjmmFOhhx56SHNQo4mQbsO6VUH87XZ0tcYmpYvovvPMOzMyx1Cqtt2R5yxXKKd8mzuZOCbV2zmRCSEhREIn/hQqzEROMMOUBil5VTITJ8ivi1CiiOdOfr1kiuB3gald8B2JqB3zaF8cRoIQkBJITO2Kx/vyoBu9pH3VpRvIRH1JgbBVl0u3serIuSTipM6rorEqHDRt10t5iCPTNBfdMaY3u7kvgAeG0af7HAQaj86ZS4Tm@n8OoeHRfK7hy24GWHcDaM9onC69Za7GIe@C7If95Zmw7v8BOyO0hv@5wrpgB1adEpOZtEGrLXJdF9PgF9RlmS4@JPoPEpU3FPE398zX7OmRb63ZxvM71rTf "Dart – Try It Online")
]