58
\$\begingroup\$

Minesweeper is a popular puzzle game where you must discover which tiles are "mines" without clicking on those tiles. Each tile is either a mine (represented by *) or a clue, i.e. a number from 0 to 8 representing how many of the 8 neighboring tiles are mines. Your task today is to take a board containing the mines and fill in all of the clues. For example, look at the following 5x4 board, with 5 mines:

 *  
*  * 
  *  
    *

After filling in the clues, the board will look like this:

2*211
*33*1
12*32
0112*

Details

You must write either a full-program or a function that takes in a grid of characters containing only spaces and asterisks and outputs another grid where each space is replaced with the number of adjacent mines (asterisks). Any of these are acceptable formats for your grids:

  • A string with newlines in it

  • A 2D list of characters/single character strings

  • A list of strings

You can assume the grid will be at least 1x1, although it is possible for it to be all mines or all spaces.

The input grid will always be padded with the appropriate number of spaces. As usual, this is , so standard loopholes apply and the shortest answer in bytes wins!

Sample IO

So that you can see the whitespace, I will show all sample IO with brackets around it.

Input:
[    * ]
[*     ]
[      ]
[      ]
[  **  ]
[ *  * ]

Output:
[1101*1]
[*10111]
[110000]
[012210]
[12**21]
[1*33*1]

Input:
[****]
[****]

Output:
[****]
[****]

Input:
[   ]
[   ]
[   ]
[   ]

Output:
[000]
[000]
[000]
[000]

Input:
[*   ]
[**  ]
[    ]
[   *]

Ouput:
[*310]
[**10]
[2221]
[001*]

Input:
[**    ]
[*    *]
[  *   ]
[      ]
[*     ]
[****  ]

Output:
[**1011]
[*4211*]
[12*111]
[121100]
[*43210]
[****10]

Input:
[     *    ]
[        * ]
[     *    ]
[**   ***  ]
[      *** ]
[          ]
[       ** ]
[  * *     ]
[*      ** ]
[       ** ]

Output:
[00001*1111]
[00002221*1]
[22102*4321]
[**102***31]
[221013***1]
[0000013542]
[0112111**1]
[12*2*12442]
[*212112**2]
[1100002**2]
\$\endgroup\$
10
  • 2
    \$\begingroup\$ FYI, I made all of the sample IO by hand, so it's possible there are some minor errors in there. Let me know if something looks off and I'll try to fix it ASAP. \$\endgroup\$
    – DJMcMayhem
    Commented Oct 23, 2016 at 4:45
  • \$\begingroup\$ Related. \$\endgroup\$
    – xnor
    Commented Oct 23, 2016 at 4:50
  • 1
    \$\begingroup\$ Can the grid be non-square ? \$\endgroup\$
    – Ton Hospel
    Commented Oct 23, 2016 at 8:56
  • \$\begingroup\$ Can the mines represented by another character? \$\endgroup\$
    – Xwtek
    Commented Oct 23, 2016 at 11:58
  • \$\begingroup\$ @ChristianIrwan No, the mines will always be an asterisk. \$\endgroup\$
    – DJMcMayhem
    Commented Oct 23, 2016 at 12:59

21 Answers 21

23
\$\begingroup\$

MATL, 18 17 bytes

Thanks to @mbomb007 for a correction in the input of test case 6

32>t3Y6Z+-6b(48+c

Input is a 2D char array, in the format

[' *   '; '*  * '; '  *  '; '    *']

Try it online!

Test cases: 1, 2, 3, 4, 5, 6.

Explanation

32>      % Input 2D char array implicitly. Transform it into a 2D logical
         % array with asterisk replaced by true and space by false
t        % Duplicate
3Y6      % Push [1 1 1; 1 0 1; 1 1 1]. This defines the neighbourhood
Z+       % 2D convolution, keeping size. Gives the number of neighbouring
         % mines for each position
-6       % Push -6
b        % Bubble up in stack
(        % Assign -6 to the entries indicated by the logical array, i.e.
         % to the positions that originally contained asterisks 
48+      % Add 48. This transforms each number of neighbouring mines
         % into its ASCII code, and -6 into 42 (ASCII code of asterisk)
c        % Convert to char. Display implicitly
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Wow. That is impressive. \$\endgroup\$ Commented Oct 24, 2016 at 15:01
  • 2
    \$\begingroup\$ Getting test case 6 would piss me off playing the actual game. \$\endgroup\$ Commented Oct 24, 2016 at 15:51
  • \$\begingroup\$ Why? Test case 6 seems the most realistic. \$\endgroup\$
    – WBT
    Commented Oct 24, 2016 at 20:57
  • \$\begingroup\$ @carusocomputing Getting test case 2 would piss me off a lot more. :P \$\endgroup\$
    – DJMcMayhem
    Commented Oct 25, 2016 at 21:09
11
\$\begingroup\$

JavaScript (ES6), 114 96 bytes

a=>a.map((s,i)=>s.replace(/ /g,(_,j)=>g(k=>(s=a[i+k])?g(k=>s[j+k]>' '):0)),g=f=>f(-1)+f(0)+f(1))

Edit: Saved 18 bytes thanks to an idea by @ETHproductions.

\$\endgroup\$
2
  • \$\begingroup\$ I think you can save a bunch by defining a function to check if an index is non-space: a=>a.map((s,i)=>s.replace(/ /g,(_,j)=>a.slice(i-!!i,i+2).reduce((t,s)=>t+(q=i=>s[i+j]>' ')(-1)+q(0)+q(1),0))) \$\endgroup\$ Commented Oct 23, 2016 at 18:38
  • \$\begingroup\$ @ETHproductions I took your idea to the extreme... I don't usually get to write function parameters! \$\endgroup\$
    – Neil
    Commented Oct 23, 2016 at 18:56
7
\$\begingroup\$

R, 127 112 bytes

function(M){a=nrow(M);for(i in seq(M))if(M[i]!="*")M[i]=sum(M[pmax(i+c(-1,1,-a+-1:1,a+-1:1),0)]=="*",na.rm=T);M}

thanks to @gtwebb and @sebastian-c for improvements.

Notable points:

Matrices are vectors in R. You don't need 2-D indexing to get elements out.

seq(M) will return a sequence of the same "length" (rows x columns) as M.

You can't mix positive and negative extraction indices in R. M[-3] is legitimate R code, but not what is desired.

Input is in the form of an R matrix. Some examples:

> M <- matrix("",5,5)
> M[3,3] <- "*"
> f(M)
     [,1] [,2] [,3] [,4] [,5]
[1,] "0"  "0"  "0"  "0"  "0" 
[2,] "0"  "1"  "1"  "1"  "0" 
[3,] "0"  "1"  "*"  "1"  "0" 
[4,] "0"  "1"  "1"  "1"  "0" 
[5,] "0"  "0"  "0"  "0"  "0" 
> M[2,2] <- "*"
> f(M)
     [,1] [,2] [,3] [,4] [,5]
[1,] "1"  "1"  "1"  "0"  "0" 
[2,] "1"  "*"  "2"  "1"  "0" 
[3,] "1"  "2"  "*"  "1"  "0" 
[4,] "0"  "1"  "1"  "1"  "0" 
[5,] "0"  "0"  "0"  "0"  "0" 
> M[3,2] <- "*"
> f(M)
     [,1] [,2] [,3] [,4] [,5]
[1,] "1"  "1"  "1"  "0"  "0" 
[2,] "2"  "*"  "3"  "1"  "0" 
[3,] "2"  "*"  "*"  "1"  "0" 
[4,] "1"  "2"  "2"  "1"  "0" 
[5,] "0"  "0"  "0"  "0"  "0" 
> 
\$\endgroup\$
4
  • 1
    \$\begingroup\$ You can cut a few characters off by using T instead of TRUE. I managed to slide some braces off one of the if functions too: f=function(M){a=nrow(M);b=ncol(M);for(i in seq(M))if(M[i]!="*")M[i]=sum(M[pmax(i+c(-1,1,-a+-1:1,a+-1:1),0)]=="*",na.rm=T);M} \$\endgroup\$ Commented Oct 24, 2016 at 16:27
  • 1
    \$\begingroup\$ You define b=ncol(M) and then don't use it so you could get rid of that. \$\endgroup\$
    – gtwebb
    Commented Oct 24, 2016 at 22:28
  • \$\begingroup\$ I can shave off four characters (and vectorise): M->{a=nrow(M);p=M=='*';M[]=ifelse(p,'*',sapply(seq(M),i->sum(p[pmax(i+c(-1,1,-a+-1:1,a+-1:1),0)],na.rm=T)))} — however, this cheats slightly because it requires a redefined <- lambda, see klmr/functional/lambda \$\endgroup\$ Commented Oct 25, 2016 at 15:02
  • \$\begingroup\$ @Konrad interesting idea, but I'll keep it to base R thanks! \$\endgroup\$
    – JDL
    Commented Oct 25, 2016 at 15:06
6
\$\begingroup\$

Java, 190 bytes

Edit:

  • -6 bytes off. Thanks to @Frozn
  • -1 byte off. Thanks to myself :)
  • -1 byte off. Also spotted some mistakes. Thanks to @Kevin Cruijssen

Snipet

c->{for(int x,y,j,i=-1;++i<c.length;)for(j=-1;++j<c[0].length;){if(c[i][j]<33){c[i][j]=48;for(x=i-2;++x<i+2;)for(y=j-2;++y<j+2;)try{if(c[x][y]==43)c[i][j]++;}catch(Exception e){}}}return c;}

Ungolfed:

public class Main{
  public static char[][] minesweeper(char[][] woclues){
    for(int i = 0; i < woclues.length ; i++){
      for(int j = 0; j < woclues[0].length ; j++){
        if( woclues[i][j] == ' '){
          woclues[i][j] = '0';
          for(int x = i - 1; x < i + 2 ; x++){
            for(int y = j - 1; y < j + 2 ; y++){
              try{
                if(woclues[x][y] == '*'){
                  woclues[i][j]++;
                }
              }catch( ArrayIndexOutOfBoundsException e){}
            }
          }
        }
      }
    }
    return woclues;
  }
  public static void main(String[]args){
    char[][] in = new char[args.length][args[0].length()];
    for(int i = 0; i < args.length;i++){
      in[i]=args[i].toCharArray();
    }
    for(char[] c:minesweeper(in)){
      System.out.println(new String(c));
    }
  }
}

Ideone it.

\$\endgroup\$
8
  • \$\begingroup\$ You can compare the char values against the ASCII values which should be shorter in most cases. You can also combine the declarations of x,y,i,j \$\endgroup\$
    – Frozn
    Commented Oct 23, 2016 at 14:00
  • \$\begingroup\$ I already did c[i][j]==32 and so on and just changed them in the Ungolfed part \$\endgroup\$ Commented Oct 23, 2016 at 14:09
  • \$\begingroup\$ And I'm shorter than Phyton. At least! \$\endgroup\$ Commented Oct 23, 2016 at 19:16
  • \$\begingroup\$ Are you sure your ungolfed code is correct? For the first test case it outputs: 0000*1\n*10011\n110000\n000000\n00**10\n0*22*1. Could you perhaps add an ideone.com test link? EDIT: Also, unless I'm doing something wrong myself, your golfed code output: ssss0s\n0sssss\nssssss\nssssss\nss00ss\ns0ss0s for the first test case (it has replaced all * with zeros..) :S \$\endgroup\$ Commented Oct 24, 2016 at 8:03
  • \$\begingroup\$ Edited. I'll add a test link as soon as my pior internet allows that to me. \$\endgroup\$ Commented Oct 24, 2016 at 8:13
5
\$\begingroup\$

JavaScript (ES6), 107

Input/output as an array of strings

f=l=>l.map((r,i)=>r.replace(/ /g,(c,j)=>(s=r=>(c+r).substr(j,3).split`*`.length,s(l[i-1])+s(l[i+1])+s(r)-3)))

note when the function s is called with an element of the list l out of the bounds, the parameter a is undefined and c+a will result in " undefined" thanks to the quirky conversion rules of javascript

More readable

l=>
  l.map(
    (r,i) =>
      r.replace(/ /g, (c,j) =>
        (
          s = a => (c+a).substr(j,3).split`*`.length,
          s(l[i-1])+s(l[i+1])+s(r)-3
        )
      )
  )
\$\endgroup\$
5
\$\begingroup\$

Python 2, 138 bytes

def f(s):w=s.find('\n')+1;print''.join([c,`(s[i-(i>0):i+2]+(w*' '+s)[i-1:i+2]+s[i-1+w:i+2+w]).count('*')`][c==' ']for i,c in enumerate(s))

Defines a function f that accepts an input string like

"  *\n** \n*  \n"

and prints a string to STDOUT:

23*
**2
*31
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Make enumerate start from 2 (enumerate(s,2)), and replace all occurrences of i + 2 with i and i - 1 with i - 3. That'll shave off a couple of bytes. \$\endgroup\$ Commented Oct 25, 2016 at 0:54
5
\$\begingroup\$

JavaScript (ES6) 186 182 177 161 152 bytes

f=a=>{for(s='',y=a[0].length;y--;)for(s=`
`+s,x=a.length;x--;)(k=>{for(t=0,i=9;i--;)t+=(a[x+i%3-1]||[])[y+i/3-1|0]==k;s=(a[x][y]<k?t:k)+s})`*`;return s}

Update

The above code for " *" returns "2*". This is fixed in the following script.

168 167 bytes

f=a=>{for(s='',y=a[0].length;y--;)for(s=`
`+s,x=a.length;x--;)a[x][y]=='*'?s='*'+s:(k=>{for(t=0,j=3;j--;)for(i=3;i--;)t+=(a[x+i-1]||1)[y+j-1]=='*';s=t+s})`*`;return s}

Try it here.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I think t+=(a[x+i%3-1]||[])[y+i/3-1|0]==k should work in a similar way and save you the try / catch part. \$\endgroup\$
    – Arnauld
    Commented Oct 23, 2016 at 11:19
  • 1
    \$\begingroup\$ @Arnauld. Actually, reading a property of literal number will not throw an error, so it can be also improved as (a[x+i%3-1]||1)[y+i/3-1|0]. \$\endgroup\$
    – sbisit
    Commented Oct 24, 2016 at 16:33
4
\$\begingroup\$

Haskell, 115 bytes

z=zip[1..]
x%i=[a|(j,a)<-z x,abs(i-j)<2]
f x=[[head$[c|c>' ']++show(sum[1|'*'<-(%j)=<<x%i])|(j,c)<-z r]|(i,r)<-z x]

Defines a function f on lists of strings

\$\endgroup\$
4
\$\begingroup\$

TSQL 292 291 bytes

Golfed:

DECLARE @ varchar(max)=
' *   
*  * 
  *  
    *';
WITH C as(SELECT x+1i,substring(@,x+1,1)v,x/z r,x%z c FROM master..spt_values CROSS APPLY(SELECT number x,charindex(char(10),@)z)z WHERE type='P'and x<len(@))SELECT @=stuff(@,i,1,z)FROM(SELECT i,(SELECT count(*)FROM C WHERE abs(D.c-c)<2and abs(D.r-r)<2and'*'=v)z FROM C D WHERE''=v)h PRINT @

Ungolfed:

DECLARE @ varchar(max)=
' *   
*  * 
  *  
    *';
WITH C as
(
  SELECT x+1i,substring(@,x+1,1)v,x/z r,x%z c
  FROM master..spt_values
  CROSS APPLY(SELECT number x,charindex(char(10),@)z)z
  WHERE type='P'and x<len(@)
)
SELECT @=stuff(@,i,1,z)
FROM
(
  SELECT
    i,
    (
      SELECT count(*)
      FROM C
      WHERE 
       abs(D.c-c)<2and abs(D.r-r)<2and'*'=v
    )z
  FROM C D
  WHERE''=v
)h
PRINT @

Fiddle

\$\endgroup\$
6
  • \$\begingroup\$ Does the ; at the front of your code count? It seems that you have counted it. \$\endgroup\$ Commented Oct 24, 2016 at 13:28
  • \$\begingroup\$ @EriktheGolfer Yes, where there is script prior to WITH. Compiler will give an error if it is removed. It is possible to test ideas in the fiddle \$\endgroup\$ Commented Oct 24, 2016 at 13:33
  • \$\begingroup\$ I mean, should it be in the byte count of the general source? Because it seems like it should be part of the "Initial STDIN" statement instead. \$\endgroup\$ Commented Oct 24, 2016 at 13:34
  • \$\begingroup\$ @EriktheGolfer I don't really know, I suppose it can be part of the declaration. Can also exclude master.. if there is a USE master in the beginning of the script. But it gives an annoying message in the fiddle. \$\endgroup\$ Commented Oct 24, 2016 at 13:38
  • \$\begingroup\$ I tried putting the semicolon on the previous line, and it worked. I assume the last line is what counts. \$\endgroup\$ Commented Oct 24, 2016 at 13:42
3
\$\begingroup\$

Python 2, 192 bytes

-3 bytes thanks to Copper, -10 bytes if modifying the input grid is allowed, another -11 bytes by getting rid of continue and another -12 bytes for eliminating the counter variable

def f(L):
 n,S,s=len(L[0]),[0,1,2],[' '];P=[s*(n+2)];K=P+[s+x+s for x in L]+P
 for y in range(len(L)):
    for x in range(n):
     if'*'!=L[y][x]:L[y][x]=`sum(K[y+d][x+e]=='*'for d in S for e in S)`

Uses a list of list of characters L and creates a padded version K, so no problem at boundaries. Indentation is

  1. Space
  2. Tab
  3. Tab+Space
  4. Tab+Tab

Usage:

s=""" *   
*  * 
  *  
    *"""
print s
s=[[c for c in x] for x in s.split('\n')]
f(s)
s='\n'.join([ ''.join(x) for x in s])
print s
\$\endgroup\$
4
  • 1
    \$\begingroup\$ A few minor golfs: you can put your first three variables assignments on the same line separated with semicolons and lose the indentation. Also, use if'*'==L[y][x]: to save a byte. \$\endgroup\$
    – Copper
    Commented Oct 23, 2016 at 11:07
  • \$\begingroup\$ If you assign r=range; on the same line as n,S,s, you can save five characters by replacing the calls to range(...) with r(...). \$\endgroup\$
    – alexwlchan
    Commented Oct 23, 2016 at 22:36
  • \$\begingroup\$ @alexwlchan doing this saves 2*ange so 8 bytes, but i have to add ,r and ,range which is also 8 bytes so nothing earned. \$\endgroup\$
    – Karl Napf
    Commented Oct 24, 2016 at 8:34
  • \$\begingroup\$ @KarlNapf Gah, you're right -- I'd forgotten about the range. \$\endgroup\$
    – alexwlchan
    Commented Oct 24, 2016 at 10:12
3
\$\begingroup\$

Ruby, 112

Takes and returns a string. String must be newline separated and newline terminated.

->s{w=1+s=~/\n/
s.size.times{|i|s[i]==' '&&(n=0;9.times{|j|(s+$/*w)[i+j%3-1+j/3*w-w]==?*&&n+=1};s[i])=n.to_s}
s}

in test program

f=->s{
  w=(s=~/\n/)+1                              #Calculate width.
  s.size.times{|i|                           #For each char in s
    s[i]==' '&&(                             #If it is a space
      n=0                                    #set counter n to 0 and visit
      9.times{|j|                            #a 3x3 square of chars.
        (s+$/*w)[i+j%3-1+j/3*w-w]==?*&&n+=1  #If *, increment n.
      }                                      #(Pad s with w newlines to avoid *'s detected by wraparound.)
      s[i]=n.to_s                            #Write n back to s in string format
    )
  }
s}                                           #Return s.

puts f[
" *   
*  * 
  *  
    *
"]
\$\endgroup\$
2
\$\begingroup\$

Racket 415 bytes

(let*((l(string->list s))(g (λ(r c)(if(or(>= r n)(>= c n)(< r 0)(< c 0))#f(list-ref l(+ c(* n r))))))(ng (λ(r c)(let*((h'(-1 0 1))(k(filter(λ(x)x)
(for*/list((i h)(j h)#:unless(= 0 i j))(g(+ r i)(+ c j))))))(count(λ(x)(equal? x #\*))k))))(k(for*/list((i n)(j n))(ng i j)))
(ol(map(λ(x y)(if(equal? x #\*)"*"(number->string y)))l k)))(for((i(* n n))(j ol))(display j)(when(= 0(modulo(add1 i)n))(displayln ""))))

Ungolfed:

(define (f s n)
  (let* ((l (string->list s))
         (get                            ; fn to get value at a (row, col)
          (lambda(r c)                   ; #f if invalid row or col
            (if (or (>= r n)
                    (>= c n)
                    (< r 0)
                    (< c 0))
                #f (list-ref l (+ c (* n r))))))

         (neighbors                      ; fn to count neighboring "*"
          (lambda(r c)
            (let* ((h '(-1 0 1))
                   (u (filter
                       (lambda(x) x)
                       (for*/list ((i h)(j h)
                                   #:unless (= 0 i j))
                         (get (+ r i) (+ c j))))))
              (count (lambda(x)(equal? x #\*)) u))))

         (k (for*/list ((i n) (j n))    ; for each row,col count neighboring "*"
              (neighbors i j)))
         (ol(map (lambda(x y)           ; get outlist- replace blanks with neighboring star count
                   (if(equal? x #\*) 
                      "*"
                      (number->string y)))
                 l k)))

    (for ((i (* n n))(j ol))            ; display outlist
      (display j)
      (when (= 0 (modulo (add1 i) n))
        (displayln "")))))

Testing (lists as a single string with column number specified; will also work with spaces):

(f "----*-*-------------------**---*--*-" 6) 

Output:

1101*1
*10111
110000
012210
12**21
1*33*1
\$\endgroup\$
2
\$\begingroup\$

PHP, 145 133 132 127 bytes

for($s=$argv[1];$s[$p];print$c)if(" "==$c=$s[$p++])for($y=-2;$y++<1;)for($x=$p-3;$x++<$p;)$c+="!"<$s[$x+$y*strpos($s,"\n")+$y];

takes input as single string, newline separated. Run with -r.

breakdown

for($s=$argv[1];$s[$p]; // loop through all characters (including newlines)
    print$c                     // 3. print result
)
    if(" "==$c=$s[$p++])        // 1. if character is space
        for($y=-2;$y++<1;)      // 2. count surrounding asterisk characters
            for($x=$p-3;$x++<$p;)
                $c+="!"<$s[$x+$y*strpos($s,"\n")+$y];
\$\endgroup\$
3
  • \$\begingroup\$ "!">$n=$s[$p] instead of " "==$n=$s[$p] saves one Byte \$\endgroup\$ Commented Oct 24, 2016 at 16:24
  • \$\begingroup\$ @JörgHülsermann That would destroy the linebreaks. \$\endgroup\$
    – Titus
    Commented Oct 24, 2016 at 16:27
  • \$\begingroup\$ @JörgHülsermann ... but the trick works for the asterisk comparison (in the new version) \$\endgroup\$
    – Titus
    Commented Oct 24, 2016 at 16:35
2
\$\begingroup\$

Turtlèd, 99 bytes

(whoops I keep forgetting the link :| )

Takes inputs with brackets around each line

Turtlèd cannot take multi-line input, so after the last line, write | to signal end of input

Note the mismatched brackets are because open brackets parse the next char as part of the bracket command

[|!.([[]r+.][[l]d)][ u]d[|[]r( #012345678#l(*+)u(*+)r(*+)r(*+)d(*+)d(*+)l(*+)l(*+)ur.)]' [[l]' d]' 

Try it online!

How it works (general description):

Until | is entered, it writes out the input on each line, with brackets to help it recognise the end of each line. After that has happened, it goes back up to the top of input. It goes through each character in input. If it is a space, it looks around the space, adding one to the counter for each bomb it finds. after each line, it deletes the brackets. When it gets to the last line, with the | in it, it stops, and deletes the |. the grid is implicitly printed.

\$\endgroup\$
2
\$\begingroup\$

Jelly, 100 62 bytes

¹3Ƥz0$€z0$3Ƥ€
=”*×56
F=”*+/+48
;” ṭ” FƊ€
Çz0Çz0Ñ3Ŀ€€_³2Ŀ¤»42Ọ

Called with and returns a 2D array of strings. Golfed this down significantly after realizing I was wasting a lot of bytes converting to and from numbers and that a 2D convolution is actually a little overkill. Just summing '*' in 3x3 windows gets the job done just as well.

Explanation:

¹3Ƥz0$€z0$3Ƥ€    # Creates the 3x3 windows
¹3Ƥ              # Breaks the input into rows of three
   z0$€          # Transposes each of those long windows
       z0$3Ƥ€    # and breaks into columns of three

=”*×56           # Helper link to find '*' in input
                 # Multiplies each finding by 56 (ascii '8') to guarantee it's as large as the largest possible element in the minesweeper grid

F=”*+/+48        # Sum each window
F                # Flatten
 =”*             # Find all '*', i.e. turn them in to 1
    +/           # Count them up
      +48        # and add to '0' for converting to char later

;” ṭ” FƊ€        # Pads an array with spaces
;”               # Append a space
   ṭ” F          # Prepend a space
       Ɗ€        # All that on each row of the input

Çz0Çz0Ñ3Ŀ€€_³2Ŀ¤»42Ọ
Ç                       # Call previous helper link to pad rows
 z0Ç                    # Transpose and call again to pad columns
    z0                  # Transpose back to original
      Ñ                 # Call first helper link to create windows
       3Ŀ€€             # Sum each window (the 3rd helper link)
           _            # Subtract
            ³2Ŀ¤        # from the second helper link (the original mine locations)
                »42     # Take each element with the maximum with '*'
                   Ọ    # Convert into characters
                        # Numbers have been bumped up to their ascii equivalents and '*' (42) put in place
\$\endgroup\$
1
\$\begingroup\$

APL (Dyalog Unicode), 24 bytes

{4⌷x←'*'=,⍵:'*'⋄+/x}⌺3 3

Try it online!

A direct stencil operation.

Input as a character matrix, output as a hybrid matrix.

Testcase converter

\$\endgroup\$
1
\$\begingroup\$

Vyxal 3 j, 11 bytes

Þȯᵛᵛ•CZᵗᶻg“

Try it Online!

get insanely golfed

input is a list of strings with ? instead of spaces because the parser breaks

Þȯᵛᵛ•CZᵗᶻg“­⁡​‎‎⁡⁠⁡‏⁠‎⁡⁠⁢‏⁠‎⁡⁠⁣‏⁠‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁢⁣‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏⁠‎⁡⁠⁣⁢‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁣⁣‏‏​⁡⁠⁡‌­
Þȯᵛᵛ•C       # ‎⁡number of adjacent mines
      Z      # ‎⁢zip with input
       ᵗᶻg   # ‎⁣dump, map, zip and reduce by minimum 
          “  # ‎⁤join on nothing
💎

Created with the help of Luminespire.

\$\endgroup\$
1
\$\begingroup\$

Uiua, 52 bytes

F←≡(⊂⊂⟜:@ )
≡↥@*-×56=@*:⍜(☇2)≡(+@0/+=@*♭)◫3_3⍜⍉F F.

As I learned Uiua I realized some pretty foolish inefficiencies in my Jelly answer, so I'll be going back to that one to reduce it some. I was attempting a 2D convolution with a neighborhood kernel but finally realized the significance of the kernel was to zero out the center element -- the mine -- but this is unnecessary because the answer for that element gets overwritten by the '*' in the end anyway.

This takes a 2D array of strings as input and outputs a 2D array of strings.

F←≡(⊂⊂⟜:@ )    # Helper function to pad a row with spaces
  ≡(       )    # For each row
     ⊂⟜:       # Join on space (prepend)
    ⊂    @      # Join on space (append)

≡↥@*-×56=@*:⍜(☇2)≡(+@0/+=@*♭)◫3_3⍜⍉F F.
                                     F. # Duplicate input and pad each row with spaces
                                 ⍜⍉     # Under transpose
                                   F    #   Pad again (so this pads columns now)
                             ◫3_3       # Get 3x3 sliding window
            ⍜(☇2)                       # Under rerank2 (window returns an array for each row of windows;
                                        #     this puts all the windows in one array)
                 ≡(         )           #   For each window
                           ♭            #     Deshape (flatten)
                      /+=@*             #     Count how many '*'s appear
                   +@0                  #     Add to '0'
           :                            # Flip; put the original input back on top
        =@*                             # Mask of original '*'s
     ×56                                # Multiply by 56 (ascii for '8', the largest possible value in the previous matrix
    -                                   # Subtract this from previous matrix
                                        # This guarantees every item that was an '*' is now '\0', leaving the rest alone
≡↥@*                                    # Take the minimum of each element with '*' (i.e. '\0'->'*' and others are untouched)
\$\endgroup\$
0
\$\begingroup\$

C, 152 150 147 145 bytes

i,j,r,c;f(B,R,C)char**B;{for(i=R*C;i--;)for(j=9;j--;){char*b=B[i/C]+i%C;r=i/C+j/3-1;c=i%C+j%3-1;r<0|c<0|r/R|c/C|*b&8||(*b=16|*b+(B[r][c]==42));}}

Input is in the form of a two-dimensional array of characters, followed by the numbers of rows and columns. The result will be returned in-place.

(Mostly) Ungolfed:

i, j, r, c;
f(B, R, C) char **B; {
    for (i = R*C; i--;)
        for (j = 9; j--;) {
            char *b = B[i/C] + i%C;
            r = i/C + j/3 - 1;
            c = i%C + j%3 - 1;
            r < 0 | c < 0 | r / R | c / C | *b & 8 ||
                (*b = 16 | *b + (B[r][c] == 42));
        }
}

The approach is straight-forward — loop over each position, loop over its neighbors, and add up all the asterisks. There are two bit-level tricks:

  • When we're deciding if a cell is an asterisk or not, we can just check if the eights-place bit is set, because the number in the cell must be less than 8 (the maximum cell value).

  • We can turn a space character into a zero character by OR-ing 16.

Edit: Golfed off two bytes by using / in place of >=.

Edit: Another five bytes by reversing the direction of the loops.

\$\endgroup\$
0
\$\begingroup\$

C#, 341 Bytes

A naïve implementation that can definitely be shortened.

s=>s=="*"?1:0;s=>{for(int i=0,j,n,l=s.Length,c=s[i].Length;i<l;++i)for(j=0;j<c;++j)if(s[i][j]!="*"){n=0;if(i>0){n+=a(s[i-1][j]);n+=j>0?a(s[i-1][j-1]):0;n+=j+1<c?a(s[i-1][j+1]):0;}n+=a(s[i][j]);n+=j>0?a(s[i][j-1]):0;n+=j+1<c?a(s[i][j+1]):0;if(i+1<l){n+=a(s[i+1][j]);n+=j>0?a(s[i+1][j-1]):0;n+=j+1<c?a(s[i+1][j+1]):0;}s[i][j]=n+"";}return s;};
\$\endgroup\$
0
\$\begingroup\$

Python 2, 183 bytes

def s(m):
 j=m.find('\n')+1;q='q'*j*2;m=list(q+m+q)
 for i in range(len(m)):
  if m[i]==' ':m[i]=`sum([m[k+i]=='*'for k in [-j-1,-j,-j+1,-1,1,j-1,j,j+1]])`
 return''.join(m)[j*2:-j*2]
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.