Invert a Minesweeper Board
CJam, 58 57 bytes

0WX]2m*qN/{'*f+z}2*f{\~@m&lt;fm&lt;W&lt;}:..+{W&lt;{_'*#'*@'*-,?}/N}/


Input should not end with a linefeed. Output contains 0 for cells without nearby mines.

Try it online in the CJam interpreter.

Idea

We start by padding the input matrix with one row and one column of asterisks.

For input

*4*
**2


this results in

*4**
**2*
****


Now we generate all possible modifications that result of rotating the rows and columns 0, -1 or 1 units up/left:

*4** **** **2* **4* **** ***2 4*** **** *2**
**2* *4** **** ***2 **4* **** *2** 4*** ****
**** **2* *4** **** ***2 **4* **** *2** 4***


We discard the "padding locations" from each rotation, i.e.,

*4* *** **2 **4 *** *** 4** *** *2*
**2 *4* *** *** **4 *** *2* 4** ***


and form a single matrix by concatenating the corresponding characters of each rotation:

******4** 4*******2 **24*****
*******4* *4****2** 2***4****


The first character of each position is its original character.


If it is a non-asterisk, it has to be replaced with an asterisk.
If it is an asterisk, the number of non-asterisks in that string is the number of neighboring mines.


How it works

0WX]2m*   e# Push the array of all vectors of {0,-1,1}^2.
qN/       e# Read all input from STDIN and split at linefeeds.
{'*f+z}2* e# Append a '*' to each row and transpose rows with columns. Repeat.
f{        e# For each vector [A B], push the modified input Q; then:
  \~      e#   Swap Q with [A B] and dump A and B on the stack.
  @m&lt;     e#   Rotate the rows of Q B units up.
  fm&lt;     e#   Rotate each row of the result A units left.
  W&lt;      e#   Discard the last row.
}         e# This pushes all nine rotations with Manhattan distance 1.
:..+      e# Concatenate the corresponding characters for each position.
{         e# For each row:
  W&lt;      e#   Discard the character corresponding to the last column.
  {       e#   For each remaining string:
    _'*#  e#     Find the first index of '*' in a copy.
    '*    e#     Push '*'.
    @'*-, e#     Count the non-asterisks in the string.
    ?     e#     Select '*' if the index is non-zero, the count otherwise.
  }/      e#
  N       e#   Push a linefeed.
}/        e#