[Question]
  [
# Heatmaps
Consider a rectangular room, on whose ceiling we have a thermal camera pointing downward. In the room, there are some number of *heat sources* of intensity `1-9`, the background temperature being `0`. The heat dissipates from each source, dropping by one unit per (non-diagonal) step. For example, the `20x10` room
```
...........1........
....................
...8................
..5...............2.
....................
.1..................
................1...
.................65.
....................
............2.......
```
contains 9 heat sources, and the temperature gradient shown by the thermal camera is
```
34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432
```
In graphical form this might look like:
![heatmap of 9 sources](https://i.stack.imgur.com/4RKN1.png)
From the gradient, we can infer the positions and intensities of some heat sources, but not all. For example, all `9`s can always be inferred, since they have the maximal temperature, and so can the `8` in this case, since it produces a local maximum in the gradient. The `2` near the right border can also be inferred, even though it is not at a local maximum, since it does not have another `2` as a neighbor. The `5`s, on the other hand, are not inferred, since their heat might as well be produced by the more intense sources near them. The `0`s are known to contain no heat sources, but all the other tiles may *potentially* contain one. Let's denote the uncertain tiles by hyphens `-`, certain heat sources by the corresponding digits, and certain empty space by periods `.`:
```
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
```
Your task shall be to produce this inferred pattern from the temperature gradient.
# Rules
You are given the input as a string delimited by either newlines or vertical pipes `|`, whichever is more convenient, and the output shall be of the same form. There may be a trailing delimiter in the input and/or output, but no preceding one. The size of the input may vary, but its width and height are always at least `4`. Both functions and full programs are acceptable. The lowest byte count wins, and standard loopholes are forbidden.
# Additional Test Cases
Input:
```
898778765432100
787667654321100
677656543211210
678765432112321
567654321123210
```
which looks like this in graphical form:
![test case 1](https://i.stack.imgur.com/COXcj.png)
Output:
```
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.
```
Input:
```
7898
8787
7676
6565
```
Output:
```
--9-
8---
----
----
```
Input:
```
00001
00000
00000
10000
```
Output:
```
....1
.....
.....
1....
```
  
[Answer]
# CJam, ~~73 69 62~~ 55 bytes
*UPDATE* : New algorithm. Shorter and more scope for improvement
```
qN/5ff*{{[{_@_@<{I'0t}*\}*]W%}%z}4fI{):X-'-X~X'.??}f%N*
```
**How it works**
The logic is similar to the algorithm below, but here I am not checking for all 4 neighbors in a single iteration. Instead, I use a smaller approach to iterate through all rows and columns in both directions. Here are the steps involved:
* Convert each character into sets of 5. The first 4 will be modified to tell if they are bigger than the adjacent cell in the row while iterating. Last one is for comparison purposes.
* Iterate on each row and reduce on each row. While reducing, I have two 5 character string. I know what kind of iteration is [0 for rows normal, 1 columns reversed, 2 for rows reversed and 3 for columns normal] I update the ith character in the first 5 character string and make it 0 if it is smaller than the second.
* After all 4 iterations, if all 5 characters are same and non-zero, that is the local maxima. I map through all 5 characters strings and convert them to either single digit, `.` or `-`.
Here is an example run on a small input:
```
7898
8787
7676
6565
```
After first step:
```
["77777" "88888" "99999" "88888"
 "88888" "77777" "88888" "77777"
 "77777" "66666" "77777" "66666"
 "66666" "55555" "66666" "55555"]
```
After second step:
```
["00777" "08888" "99999" "88088"
 "88888" "07007" "88808" "77007"
 "77707" "06006" "77707" "66006"
 "66606" "05005" "66606" "55005"]
```
After last mapping to single character, final output:
```
--9-
8---
----
----
```
**Code Explanation**:
```
qN/5ff*                         "Split the input on new line and convert each character";
                                "to string of 5 of those characters.";
{{[{             }*]W%}%z}4fI   "This code block runs 4 times. In each iteration, it";
                                "maps over each row/column and then for each of them,";
                                "It reduce over all elements of the row/column";
                                "Using combination of W% and z ensures that both rows and";
                                "columns are covered and in both directions while reducing";
    _@_@                        "Take a copy of last two elements while reducing over";
        <                       "If the last element is bigger than second last:";
         {I'0t}*\               "Convert the Ith character of the 5 char string of"
                                "second last element to 0";
                                "We don't have to compare Ith character of last two 5 char";
                                "string as the smaller one will be having more leading";
                                "0 anyways. This saves 4 bytes while comparing elements";
{):X-'-X~X'.??}f%N*             "This part of code converts the 5 char back to single char";
 ):X                            "Remove the last character and store in X. This last char";
                                "was not touched in the prev. loop, so is the original char";
    -                           "Subtract X from remaining 4 char. If string is not empty";
                                "then it means that it was not all same characters";
                                "In other words, this character was smaller then neighbors";
     '-      ?                  "If non-empty, then replace with - else ...";
       X~X'.?                   "if int(X) is zero, put . else put X";
               f%N*             "The mapping code block was run for each row and then";
                                "The rows are joined by newline.";
```
[Try it here](http://cjam.aditsu.net/#code=qN%2F5ff*%7B%7B%5B%7B_%40_%40%3C%7BI'0t%7D*%5C%7D*%5DW%25%7D%25z%7D4fI%7B)%3AX-'-X~X'.%3F%3F%7Df%25N*&input=34565432100100000000%0A45676543210000000000%0A56787654321000000110%0A45676543210000001221%0A34565432100000012321%0A23454321000000123432%0A12343210000001234543%0A01232100000012345654%0A00121000000011234543%0A00010000000121123432)
---
**Older approach**
```
qN/~_,):L0s*]0s*:Q_,{QI=:A[W1LL~)]If+Qf=$W=<'-A?A~\'.?I\t}fIL/W<Wf<N*
```
**How it works**
The logic is simple, iterate through the grid and see if the current value is greater or equal to the remaining four neighbors - up, down, left and right. Then transform the current value based on the above rule and if the value is equal to 0, make it "." .
**Code Explanation**
```
qN/~_,):L0s*]0s*:Q         "This part of code pads the grid with 0s";
qN/~                       "Read the input, split on new lines and unwrap the arrays";
    _,):L                  "Copy the last row, taken length, increment and store in L";
         0s*               "Get L length 0 string";
            ]0s*           "Wrap everything in an array and join the rows by 0";
                :Q         "Store this final single string in Q";
_,{        ...      }fI    "Copy Q and take length. For I in 0..length, execute block";
   QI=:A                   "Get the I'th element from Q and store in A";
   [WiLL~)]If+             "This creates indexes of all 4 neighboring cells to the Ith cell";
              Qf=          "Get all 4 values on the above 4 indexes";
                 $W=       "Sort and get the maximum value";
<'-A?                      "If the current value is not the largest, convert it to -";
     A~\'.?                "If current value is 0, convert it to .";
           I\t             "Update the current value back in the string";
{ ... }fIL/                "After the loop, split the resulting string into chunks of L";
           W<Wf<           "Remove last row and last column";
                N*         "Join by new line and auto print";
```
[Try it online here](http://cjam.aditsu.net/#code=qN%2F~_%2C)%3AL0s*%5D0s*%3AQ_%2C%7BQI%3D%3AA%5BW1LL~)%5DIf%2BQf%3D%24W%3D%3C'-A%3FA~%5C'.%3FI%5Ct%7DfIL%2FW%3CWf%3CN*&input=34565432100100000000%0A45676543210000000000%0A56787654321000000110%0A45676543210000001221%0A34565432100000012321%0A23454321000000123432%0A12343210000001234543%0A01232100000012345654%0A00121000000011234543%0A00010000000121123432)
[Answer]
# JavaScript (ES6) 99
```
F=h=>[...h].map((c,i)=>[o=~h.search('\n'),-o,1,-1].some(d=>h[d+i]>c)&c>0?'-':c=='0'?'.':c).join('')
```
**Test** In Firefox/FireBug console
```
console.log(F('\
34565432100100000000\n\
45676543210000000000\n\
56787654321000000110\n\
45676543210000001221\n\
34565432100000012321\n\
23454321000000123432\n\
12343210000001234543\n\
01232100000012345654\n\
00121000000011234543\n\
00010000000121123432\n'),'\n\n',
F('\
898778765432100\n\
787667654321100\n\
677656543211210\n\
678765432112321\n\
567654321123210\n'), '\n\n',
F('7898\n8787\n7676\n6565\n'))
```
*Output*
```
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.
--9-
8---
----
----
```
[Answer]
# Python 2: 154 byte
```
b=input()
l=b.index('\n')+1
print''.join(('\n.'+('-'+v)[all([v>=b[j]for j in i-l,i-1,i+l,i+1if 0<=j<len(b)])])[('\n0'+v).index(v)]for i,v in enumerate(b))
```
Input has to be of the form `"00001\n00000\n00000\n10000"`. 
Converting a string to a 2D-matrix is quite lengthy in Python. So I keep the original string format. I enumerate over the input, `i` is the index, `v` is the char (Finally enumerate saved bytes in a golf solution!!). For each pair `(i,v)` I compute the correct char of output, and join them. How do I choose the correct output char? If `v == '\n'`, the output char is `\n`, it `v == '0'`, than the output char is `'.'`. Otherwise I test the 4 neighbors of `v`, which are `b[i-b.index('\n')-1]` (above), `b[i-1]` (left, `b[i+1]` (right) and `b[i+b.index('\n')+1]` (under), if they are `<= v` and choose the char `'-'` or `v`. Here I'm comparing chars not the numbers, but it works quite fine, because the ascii values are in the correct order. Also there are no problems, if `b[i-1]` or `b[i+1]` equal `'\n'`, because `ord('\n') = 10`. 
# Pyth: ~~61~~ 58
```
JhxQbVQK@QN~k@++b\.?\-f&&gT0<TlQ<K@QT[tNhN-NJ+NJ)Kx+b\0K)k
```
More or less a translation of the Python script. Quite ugly ;-)
Try it online: [Pyth Compiler/Executor](https://pyth.herokuapp.com/) Same input format as the Python solution. 
```
JhxQb      Q = input()
  xQb      Q.index('\n')
 h         +1
J          store in J
VQK@QN~k.....)k   k is initialized as empty string
VQ           )    for N in [0, 1, 2, ..., len(Q)-1]:
  K@QN                K = Q[n]
      ~k              k += ... (a char, computed in the next paragraph)
             )    end for
              k   print k
@...x+b\0K   ... is a char of len 3 (is constructed below)
     +b\0    the string "\n0"
    x    K   find Q[d] in this string and return index, if not found -1
@...         lookup in string at the computed position (this is done mod 3 automatically!)
++b\.?\-f&&gT0<TlQ<K@QT[tNhN-NJ+NJ)K   not to the string
                       [tNhN-NJ+NJ)    the list [d-1, d+1, d-J, d+j]
        f                              filter the list for indices T which
           gT0                            T >= 0
          &                               and
              <TlQ                        T < len(Q)
         &                                and
                  <K@QT                   Q[d] < Q[T]
     ?\-                           K   use "-" if len(filter) > 0 else Q[d]
                                       this creates the third char
++b\.                                  "\n" + "." + third char
```
[Answer]
# Perl, ~~77, 75, 72~~ 70
Standard 2d regex matching tricks.
```
#!perl -p0
/
/;$x="(.{@-})?";y/0/./while s/$.$x\K$"|$"(?=$x$.)/-/s||($"=$.++)<9
```
Example:
```
$ perl heat.pl <in.txt
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
```
Try it [here](https://ideone.com/XQdGdR)
[Answer]
# Java, ~~307~~, ~~304~~, ~~303~~, ~~299~~ 298
This is for sure a "perfect" challenge for some Java codegolf :)
```
class M{public static void main(String[]a){int c=a[0].indexOf('|'),i=c,d,v;char[]r=a[0].replace("|","").toCharArray(),m=new char[(v=r.length+c)+c];for(;i<v;){m[i]=r[i++-c];}for(i=c;i<v;i++){a[0]=i%c<1?"\n":"";d=m[i];System.out.print(a[0]+(d<49?'.':m[i-c]>d|m[i+c]>d|m[i-1]>d|m[i+1]>d?'-':m[i]));}}}
```
**Input (pipe '|' method):**
```
34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432
```
**Output:**
```
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
```
[Answer]
# APL, 92
```
('.-',⎕D)[1+(M≠0)+M{(1+⍺)×0≠⍺∧M[J/⍨Z∊⍨J←⍵∘+¨(⌽¨,+)(-,+)⊂0 1]∧.≤⍺}¨Z←⍳⍴M←↑{×⍴⍵:(⊂⍎¨⍵),∇⍞⋄⍬}⍞]
```
Example:
```
       ('.-',⎕D)[1+(M≠0)+M{(1+⍺)×0≠⍺∧M[J/⍨Z∊⍨J←⍵∘+¨(⌽¨,+)(-,+)⊂0 1]∧.≤⍺}¨Z←⍳⍴M←↑{×⍴⍵:(⊂⍎¨⍵),∇⍞⋄⍬}⍞]
34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
```
[Answer]
# Ruby 140
```
f=->s{
r=s.dup
l=s.index(?\n)+1
(0...s.size).map{|i|
s[i]<?0||r[i]=r[i]<?1??.:[i-1,i+1,i-l,i+l].map{|n|n<0??0:s[n]||?0}.max>r[i]??-:s[i]}
r}
```
Nothing special; just iterate through the map and compare the current value with the value of the four neighbors.
Run it online with tests: <http://ideone.com/AQkOSY>
[Answer]
# R, 223
About the best I can come up with at the moment. Dealing with the string is quite expensive. I think there is room for improvement, but can't see it at the moment
```
s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')
```
Test Result
```
> s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')
1: 898778765432100|787667654321100|677656543211210|678765432112321|567654321123210
2: 
Read 1 item
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.
> s=strsplit;a=c(m<-do.call(rbind,s(s(scan(w="c"),'|',T)[[1]],'')));w=(d<-dim(m))[1];n=c(-1,1,-w,w);cat(t(array(sapply(seq(a),function(x)if(a[x]>0)if(any(a[(n+x)[which(n+x>0)]]>a[x]))'-'else a[x]else'.'),d)),fill=d[2],sep='')
1: 34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432
2: 
Read 1 item
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
> 
```
[Answer]
## J - 69 bytes
```
[:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2
```
Examples:
```
   ([:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2) (0 : 0)
34565432100100000000
45676543210000000000
56787654321000000110
45676543210000001221
34565432100000012321
23454321000000123432
12343210000001234543
01232100000012345654
00121000000011234543
00010000000121123432
)
---------..1........
----------..........
---8-------......--.
----------......--2-
---------......-----
--------......------
-------......-------
.-----......-----6--
..---.......--------
...-.......-2-------
   ([:u:45+[:(+2 0 3{~"#1+*)@((]*]=(0,(,-)1 0,:0 1)>./@:|.])-0=])"."0;._2) (0 : 0)
898778765432100
787667654321100
677656543211210
678765432112321
567654321123210
)
-9---8-------..
-------------..
--------------.
--8---------3--
-----------3--.
```
PS: the `(0 : 0)` is the standard J way of specifying strings. You might as well use `|` delimited strings (with a trailing `|`).
[Answer]
# Excel VBA - 426
It'll be a rare occasion that VBA wins any code golf games, but as it's what I use the most, it's fun to play around with it. The first line is an edge case that made this longer than it seems it should have to be.
```
Sub m(a)
    b = InStr(a, "|")
    For i = 1 To Len(a)
        t = Mid(a, i, 1)
        Select Case t
            Case "|"
                r = r & "|"
            Case 0
                r = r & "."
            Case Else
                On Error Resume Next
                x = Mid(a, i - 1, 1)
                y = Mid(a, i + 1, 1)
                Z = Mid(a, i + b, 1)
                If i < b Then
                    If t < x Or t < y Or t < Z Then
                        r = r & "-"
                    Else
                        r = r & t
                    End If
                Else
                    If t < x Or t < y Or t < Z Or t < Mid(a, i - b, 1) Then
                        r = r & "-"
                    Else
                        r = r & t
                    End If
                End If
        End Select
    Next
    MsgBox r
End Sub
```
The count doesn't include initial line whitespace.
I played around with the idea of sending the input to a sheet and working from there, but I think looping the passed string character-by-character saves code.
Call from Immediate Window:
```
m "34565432100100000000|45676543210000000000|56787654321000000110|45676543210000001221|34565432100000012321|23454321000000123432|12343210000001234543|01232100000012345654|00121000000011234543|00010000000121123432"
```
Output (in a Window):
```
---------..1........|----------..........|---8-------......--.|----------......--2-|---------......-----|--------......------|-------......-------|.-----......-----6--|..---.......--------|...-.......-2-------
```
[Answer]
## Perl - 226
```
sub f{for(split'
',$_[0]){chomp;push@r,r($_);}for(t(@r)){push@y,r($_)=~s/0/./gr}$,=$/;say t(@y);}sub r{$_[0]=~s/(?<=(.))?(.)(?=(.))?/$1<=$2&&$3<=$2?$2:$2eq'0'?0:"-"/ger;}sub t{@q=();for(@_){for(split//){$q[$i++].=$_;}$i=0;}@q}
```
You can try it on [ideone](https://ideone.com/feK1Uc). If anyone is interested in an explanation, let me know.
[Answer]
# Haskell - 193
```
z='0'
r=repeat z
g s=zipWith3(\u t d->zip3(zip(z:t)u)t$zip(tail t++[z])d)(r:s)s$tail s++[r]
f=unlines.map(map(\((l,u),t,(r,d))->case()of _|t==z->'.'|maximum[u,l,t,r,d]==t->t|0<1->'-')).g.lines
```
`f` is a funtion that takes a string in the form `0001\n0000\n0000\n1000` and returns the required string.
`g` is a function that takes a list of lists of chars and returns a list of lists of ((left, up), this, (right, down)).
]