31
\$\begingroup\$

Minesweeper is a puzzle game where mines are hidden around a board of nondescript tiles with the goal of identifying the location of all mines. Clicking on a mine loses the game, but clicking on any other tile will reveal a number from 0-8 which signifies how many mines directly surround it.

Given a number, you must display a random* possible combination of empty tiles and mines surrounding it. This should be in the form of a 3x3 array. The center tile should be the number of mines taken as input.

*Must have a non-zero chance for all combinations to occur.


Examples

_ = blank square
X = mine

0

___
_0_
___

1

_X_
_1_
___

1

___
_1_
X__

___
_1_
__X

4

_X_
X4X
_X_

4

X_X
_4_
X_X

4

___
X4X
X_X

8

XXX
X8X
XXX

Input

  • The number of mines surrounding the center tile (0-8)

Output

  • Any reasonable form of output that displays the 3x3 array of tiles

Other rules

  • Each combination does not have to have an equal chance of happening. There just must be a non-zero chance of each combination to occur when executing your program.
  • Any 2 characters can be chosen for the mine and empty tile.
  • This is code golf, the program with fewest bytes wins.
\$\endgroup\$
  • \$\begingroup\$ "Any 2 characters can be chosen for the mine and empty tile" may we still use, say, 1 and 0? \$\endgroup\$ – Jonathan Allan Jun 3 '18 at 1:10
  • 3
    \$\begingroup\$ @JonathanAllan I'll say yes, the 0/1 input cases might be a little bit confusing but I don't think it's a big deal. \$\endgroup\$ – aoemica Jun 3 '18 at 1:23
  • \$\begingroup\$ is a flat, 9-element list a 'reasonable form of output'? \$\endgroup\$ – Chas Brown Jun 3 '18 at 2:50
  • \$\begingroup\$ @ChasBrown no, a flat list is not really equivalent. \$\endgroup\$ – aoemica Jun 3 '18 at 3:44

21 Answers 21

4
\$\begingroup\$

Jelly, 9 bytes

<Ɱ8Ẋs4js3

Try it online!

empty = 1
mine = 0

Note that 1 and 0 are integers.

Another note: this is somewhat similar to Jonathan Allan's 10-byte answer, but it's not really influenced by it in any way, and the mechanism, if you pay close attention, is actually more different than at first glance.

\$\endgroup\$
  • \$\begingroup\$ Ugh I missed a trick :) \$\endgroup\$ – Jonathan Allan Jun 3 '18 at 19:07
  • \$\begingroup\$ @JonathanAllan Do you believe this is close enough to yours? The suffix is the same anyway... \$\endgroup\$ – Erik the Outgolfer Jun 3 '18 at 19:08
  • 1
    \$\begingroup\$ It's slightly different. If I read a post and find a quick golf I comment; if I'm just trying to solve the challenge I post. I've posted identical code before independently. \$\endgroup\$ – Jonathan Allan Jun 3 '18 at 19:15
  • \$\begingroup\$ @JonathanAllan My approach to that is a bit different, if I find out that my independent solution is actually almost the same as somebody else's but with a slightly different element which saves a byte or two (subjective opinion ensues), I comment, otherwise I outgolf. That's why I had asked, but you seem to prefer me posting it here, so... \$\endgroup\$ – Erik the Outgolfer Jun 3 '18 at 19:20
9
\$\begingroup\$

APL (Dyalog Unicode), 28 15 bytes

-13 bytes thanks to ngn!

{3 3⍴5⌽⍵,⍵≥8?8}

Explanation:

{...} A direct function (D-Fn), is its right argument.

8?8 deal 8 random numbers from the list 1..8:

      8?8                         
7 2 1 8 4 6 5 3

⍵≥ is the argument greater or equal to each of them?:

      5 ≥ 7 2 1 8 4 6 5 3   
0 1 1 0 1 0 1 1

⍵, prepend the argument to the boolean list:

      5 , 0 1 1 0 1 0 1 1
5 0 1 1 0 1 0 1 1

5⌽ rotate the list 5 positions to the left, so that the argument is in the center:

      5 ⌽ 5 0 1 1 0 1 0 1 1
1 0 1 1 5 0 1 1 0

3 3⍴ reshape the list to a 3x3 matrix:

      3 3 ⍴ 1 0 1 1 5 0 1 1 0
1 0 1
1 5 0
1 1 0

Try it online!

J, 15 bytes

Also many bytes thanks to ngn!

3 3$5|.],]>8?8:

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ (8↑1⍴⍨⍵)[8?8] -> ⍵>8?8 (assuming ⎕io←0) \$\endgroup\$ – ngn Jun 3 '18 at 17:49
  • 1
    \$\begingroup\$ 3 3⍴1↓,⍵,2 4⍴ -> 3 3⍴5⌽⍵, \$\endgroup\$ – ngn Jun 3 '18 at 17:51
  • \$\begingroup\$ @ngn Thanks! I feel ashamed by my verbose attempt... \$\endgroup\$ – Galen Ivanov Jun 3 '18 at 18:23
  • 1
    \$\begingroup\$ no need for shame :) thank you - this answer gave me an opportunity to learn some J \$\endgroup\$ – ngn Jun 3 '18 at 18:36
  • 1
    \$\begingroup\$ that J answer is really lovely. \$\endgroup\$ – Jonah Jun 4 '18 at 5:07
8
\$\begingroup\$

JavaScript (ES6), 67 bytes

Shorter version suggested by @tsh

Empty slots are 0, mines are 1.

n=>`___
_${t=9,n}_
___`.replace(/_/g,_=>n-(n-=Math.random()<n/--t))

Try it online!


Original trial-and-error version, 78 bytes

Empty slots are _, mines are 7.

f=(n,o=`___
_${k=n}_
___`.replace(/_/g,c=>Math.random()<.5?--k|7:c))=>k?f(n):o

Try it online!

Commented

f = (                         // f = recursive function
  n,                          // n = input
  o = `___\n_${k = n}_\n___`  // o = minesweeper field / k = backup of n
    .replace(/_/g, c =>       // for each underscore character c in o:
      Math.random() < .5 ?    //   random action:
        --k | 7               //     either decrement k and yield 7
      :                       //   or:
        c                     //     let the underscore unchanged
    )                         // end of replace()
) =>                          //
  k ?                         // if k is not equal to 0:
    f(n)                      //   try again
  :                           // else:
    o                         //   stop recursion and return o
\$\endgroup\$
6
\$\begingroup\$

Jelly,  13  10 bytes

8Ẉ>RẊs4js3

The returned list of lists has the displayed integer in the centre surrounded by 0s and 1s representing mines and blanks respectively.

Try it online! (footer pretty prints the array)

How?

8Ẉ>RẊs4js3 - Link: integer, n                   e.g.  3
8          - eight                                    8
 Ẉ         - length of each (implicit range of eight) [1,1,1,1,1,1,1,1]
   R       - range of n                               [1,2,3]
  >        - greater than? (vectorises)               [0,0,0,1,1,1,1,1]
    Ẋ      - shuffle                                  [1,1,1,0,0,1,1,0]
     s4    - split into chunks of 4                   [[1,1,1,0],[0,1,1,0]]
       j   - join (with n)                            [1,1,1,0,3,0,1,1,0]
        s3 - split into chunks of 3                   [[1,1,1],[0,3,0],[1,1,0]]
\$\endgroup\$
  • 1
    \$\begingroup\$ As a small note, ŒH also works in place of s4. \$\endgroup\$ – Mr. Xcoder Jun 3 '18 at 6:24
  • \$\begingroup\$ ;ṙ4s3 also works \$\endgroup\$ – dylnan Jun 3 '18 at 17:53
  • \$\begingroup\$ @dylnan I actually posted with a TIO having that same code at one point during my golfing (but quickly put it back so I didn't have to rewrite the explanation). \$\endgroup\$ – Jonathan Allan Jun 3 '18 at 19:06
6
\$\begingroup\$

Pyth, 16 14 bytes

c3jQc2.S.[d8*N

Saved 2 bytes thanks to isaacg.
Uses spaces for safe spots and quotes for mines.
Try it here

Explanation

c3jQc2.S.[d8*N
            *NQ     Get (implicit) input number of quotes...
        .[d8        ... and pad to length 8 with spaces.
      .S            Shuffle.
  jQc2              Stick the input in the middle.
c3                  Split into three.
\$\endgroup\$
  • \$\begingroup\$ .[d8 instead of >8+*8d \$\endgroup\$ – isaacg Jun 3 '18 at 3:25
5
\$\begingroup\$

Oracle 18 SQL, 230 bytes

Not a golfing language but...

WITH v(v)AS(SELECT*FROM SYS.ODCINUMBERLIST(0,1))SELECT v.v||b.v||c.v||'
'||d.v||n||e.v||'
'||f.v||g.v||h.v
FROM n,v,v b,v c,v d,v e,v f,v g,v h
WHERE v.v+b.v+c.v+d.v+e.v+f.v+g.v+h.v=n
ORDER BY DBMS_RANDOM.VALUE
FETCH NEXT ROW ONLY

The input value is in a table n with column n:

CREATE TABLE n(n) AS
SELECT 7 FROM DUAL;

Try it online - log onto https://livesql.oracle.com and paste it into a worksheet.

Output:

V.V||B.V||C.V||''||D.V||N||E.V||''||F.V||G.V||H.V
-------------------------------------------------
101 
171 
111

To get all possible combinations (183 Bytes):

WITH v(v)AS(SELECT*FROM SYS.ODCINUMBERLIST(0,1))SELECT v.v||b.v||c.v||'
'||d.v||n||e.v||'
'||f.v||g.v||h.v
FROM n,v,v b,v c,v d,v e,v f,v g,v h
WHERE v.v+b.v+c.v+d.v+e.v+f.v+g.v+h.v=n

Output:

V.V||B.V||C.V||''||D.V||N||E.V||''||F.V||G.V||H.V
-------------------------------------------------
111 
171 
110

111 
171 
101

111 
171 
011

111 
170 
111

111 
071 
111

110 
171 
111

101 
171 
111

011 
171 
111
\$\endgroup\$
3
\$\begingroup\$

Japt, 13 bytes

çÊú8 öÊi4U ò3

Try it


Explanation

                   :Implicit input of integer U
 Ê                 :"l"
ç                  :Repeat U times
  ú8               :Pad right to length 8
    öÊ             :Random permutation
       i4U         :Insert U at index 4
            ò3     :Split at every 3rd character
\$\endgroup\$
3
\$\begingroup\$

QBasic 1.1, 206 186 bytes

RANDOMIZE TIMER
INPUT N
O=N
Z=8-N
FOR I=0TO 7
IF O*Z THEN
R=RND<.5
O=O+R
Z=Z-1-R
A(I)=-R
ELSEIF O THEN
O=O-1
A(I)=1
ELSE
Z=Z-1
A(I)=0
ENDIF
NEXT I
?A(0)A(1)A(2)
?A(3)N;A(4)
?A(5)A(6)A(7)

-20 thanks to DLosc (newly-posted golfing trick).

Empty = 0
Mine = 1

Note that 0 and 1 are integers, but I'm using STDOUT anyway, so...

Output appears like this:

 A  B  C
 D  x  E
 F  G  H

Where A-H are 0/1 and x is the input.

\$\endgroup\$
  • \$\begingroup\$ Nice trick, working with QBasic's wonky number output by using numbers for the mine & empty tile! \$\endgroup\$ – DLosc Jun 4 '18 at 15:26
3
\$\begingroup\$

Charcoal, 19 bytes

W¬⁼ΣIKA⁸«E³⭆³‽²↑↗↖θ

Try it online! Link is to verbose version of code. Uses 0 for a mine, 1 for an empty space. Explanation:

     KA             Peek the entire canvas
    I               Cast to integer
   Σ                Take the sum
       ⁸            Literal 8
  ⁼                 Equals
 ¬                  Logical Not
W       «           While
          ³ ³       Literal 3
         E          Map over implicit range
           ⭆        Map over implicit range and join
              ²     Literal 2
             ‽      Random element of implicit range
                    Implicitly print on separate lines
               ↑↗↖θ Print the original input in the middle
  • Peek returns an array of strings, which Sum simply concatenates, which is why we have to cast to integer first. (Sum(Sum(PeekAll())) also works.)
  • Sum returns None for an empty array (first loop), so the only safe comparison is Not(Equals(...)).
  • Nilary Random always returns 0, although its documentation says otherwise.

Alternative solution, was 19 bytes, now 17 bytes after a Charcoal bugfix:

θ←9W⁻ΣIKA⁸UMKMI‽²

Try it online! Link is to verbose version of code. Uses 0 for a mine, 1 for an empty space. Explanation:

θ

Print the original input.

←9

Print a 9 leftwards. This moves the cursor back over the original input, and also forces at least one iteration of the while loop (otherwise an input of 8 would do nothing).

W⁻ΣIKA⁸

Repeat while the difference between the sum of all the digits on the canvas and 8 is nonzero:

UMKMI‽²

Replace each of the surrounding characters randomly with 0 or 1.

\$\endgroup\$
3
\$\begingroup\$

R, 67 63 62 59 bytes

matrix(c(sample(rep(1:0,c(n<-scan(),8-n))),n),6,5)[2:4,1:3]

Try it online!

Uses 1 and 0. Build a n* 1 +(8-n)* 0 vector, shuffles it, appends n, builds the bigger matrix shown below(where a...i stand for the elements of the original vector) and extracts the proper sub-matrix shown in uppercase:

     [,1] [,2] [,3] [,4] [,5]
[1,] "a"  "g"  "d"  "a"  "g" 
[2,] "B"  "H"  "E"  "b"  "h" 
[3,] "C"  "I"  "F"  "c"  "i" 
[4,] "D"  "A"  "G"  "d"  "a" 
[5,] "e"  "b"  "h"  "e"  "b" 
[6,] "f"  "c"  "i"  "f"  "c"
\$\endgroup\$
  • \$\begingroup\$ One byte shorter: matrix((c(sample(rep(1:0,c(n<-scan(),8-n))),n))[c(1:4,9:5)],3) \$\endgroup\$ – Gregor Jun 4 '18 at 19:47
  • 1
    \$\begingroup\$ @Gregor you're right an array is probably a reasonable form of output to display an array :) \$\endgroup\$ – JayCe Jun 4 '18 at 19:55
2
\$\begingroup\$

Python 2, 93 bytes

from random import*
def f(n):a=[1]*n+[0]*(8-n);shuffle(a);a[4:4]=[n];return zip(*[iter(a)]*3)

Try it online!

0 for empty; 1 for a mine; and n for one's self.

\$\endgroup\$
  • \$\begingroup\$ The use of iter is smart! \$\endgroup\$ – Jonathan Allan Jun 3 '18 at 13:54
  • \$\begingroup\$ @Jonathan Allan: xnor showed me that just the other day. \$\endgroup\$ – Chas Brown Jun 3 '18 at 18:40
2
\$\begingroup\$

Attache, 51 bytes

{[3,3]&Rotate[Sample[{Sum@_=_2}&_\BinBelow@8]'_,4]}

Try it online!

Explanation

Similar to Galen's J/APL answer, the basic technique is to generate an array of 1s and 0s with the correct number of mines, inserting the input by appending it to the end, rotating the array such that the input lies in the center, then reshaping into a 3x3 matrix.

Part 1: generating the binary array

There are many ways to go about doing this, but I mainly happened across two types: brute force and selection.

The primary brute force method looks like this:

NestWhile[{Random[8&2]},0,{Sum@_/=_2}&_]

This generates random arrays of 8 binary digits (Random[8&2]) while their sums do not equal the input {Sum@_/=_2}&_. This is a bit verbose, as the following emphasized portions of the code are there "just to make it work":

NestWhile[{Random[8&2]},0,{Sum@_/=_2}&_]
          ^           ^^^^^        ^^^^

And I discarded the idea.

Selection is more interesting. The main concept is to use the BaseBelow[b, n] builtin, which generates a list of all base-b integers of width n (as digit arrays), from 0 to b^n-1. For example, BaseBelow[3, 2] generates all ternary integers of width 2:

A> BaseBelow[3, 2]
 0 0
 0 1
 0 2
 1 0
 1 1
 1 2
 2 0
 2 1
 2 2

We specifically use BaseBelow[2, 8] for all binary integers of width 8. These represent all possible minefields of all lengths. This is the first step.

The second step is selecting all such arrays with only N 1s, where N is the input. My first idea was to translate this English statement directly into Attache:

Chunk[SortBy[Sum,BaseBelow[2,8]],Sum]@N@1

However, not only did this come out to be 1 byte longer than the aforementioned approach, it's also highly repetitive—and it isn't even randomized yet!. Sure, I could probably save 1 byte by reorganizing how BaseBelow is called, but it simply isn't worth using the approach.

So I decided to kill two birds with one stone and use a Shuffle based approach. The following gives all valid minefields of length N in random order:

{Sum@_=_2}&N\Shuffle[BaseBelow&8!2]

Then, all that needs to be done is to select the first. But I can do better—surely it'd be better to simply Sample the filtered array? This approach comes out to be something like this:

Sample[{Sum@_=_2}&_\BaseBelow[2,8]]

I had to revert the BaseBelow&8!2 golf because \s precedence is too high. Otherwise satisfied, I proceeded to chop a byte off of that:

Sample[{Sum@_=_2}&_\2&BaseBelow@8]

(I discovered another way to succinctly call a dyadic function here: x&f@y is a high-precedence expression which evaluates to f[x, y].)

However, despite this, I remembered that, all along, an alias for 2&BaseBelow existed: BinBelow. So I used that:

Sample[{Sum@_=_2}&_\BinBelow@8]

This generates the desired minefield. I'm convinced this is near optimal.

Part 2: Forming the array

As said earlier, the forming technique I used is similar to the J/APL answer, so I won't go into too much detail. Suppose MINEFIELD is the result from the last section. The function then becomes:

{[3,3]&Rotate[MINEFIELD'_,4]}

MINEFIELD'_ concatenates the minefield with the original input _, giving us something like this:

[1, 0, 0, 0, 1, 0, 0, 1, 3]

Then, Rotate[MINEFIELD'_,4] rotates this list 4 times to the left, placing the center:

[1, 0, 0, 1, 3, 1, 0, 0, 0]

The last step is using [3,3]& to reshape the list into a 3x3 matrix:

 1 0 0
 1 3 1
 0 0 0
\$\endgroup\$
2
\$\begingroup\$

Java 10, 165 157 141 bytes

n->{var r="___\n_"+n+"_\n___";for(int i;n>0;r=r.charAt(i*=Math.random())>58?r.substring(0*n--,i)+(i>9?0:0+r.substring(i+1)):r)i=11;return r;}

Empty tiles are _ (any character with a unicode value above 58 is fine) and mines are 0.

Try it online.

Explanation:

n->{                           // Method with integer parameter and String return-type
  var r="___\n_"+n+"_\n___";   //  Result-String, starting at:
                               //   "___
                               //    _n_
                               //    ___"
  for(int i;n>0                //  Loop as long as `n` isn't 0 yet:
      ;                        //    After every iteration:
       r=r.charAt(i*=Math.random())
                               //     Select a random integer in the range [0,11)
         >58?                  //     And if the character at this random index is a '_':
          r.substring(0*n--,i) //      Set `r` to the first part excluding character `i`,
                               //      (and decrease `n` by 1 in the process)
          +(i>9?0:0+           //      appended with a '0',
           r.substring(i+1))   //      appended with the second part
         :                     //     Else:
          r)                   //      Leave `r` unchanged
     i=11;                     //   Set `i` to 11 so a new random integer can be chosen
  return r;}                   //  Return the result
\$\endgroup\$
2
\$\begingroup\$

PowerShell, 77 bytes

param($n)-join(0..7|random -c 8|%{'X_'[$_-ge$n]
$n[++$i-ne4]
'
'*($i-in3,5)})

Try it online!

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

PHP, 135 134 123 117 122 121 bytes

Looping over str to print instead saves 1 byte

str_split and implode to insert the centre number saves 11 bytes

Don't need to assign the string to $s anymore saving 6 bytes
Yes you do. Otherwise the string is shuffled after every echo...

Removing whitespace after echo saves 1 byte

Replacing "\n" with an ctual line break saves 1 byte

$n=$argv[1];$s=implode($n,str_split(str_shuffle(str_pad(str_repeat(m,$n),8,n)),4));for(;$i<9;)echo$s[$i].(++$i%3?"":"
");

Try it online!

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

Alice, 24 bytes

a8E/be?SZ!@
~E-\ita*.o/a

Try it online!

Empty slots are 9, and mines are 0.

I also made a 27-byte program with 1 for mines and 0 for empty slots:

a8Ea8/be?SZ!@
-E-9:\ita*.o/

Try it online!

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

PowerShell, 91 86 bytes

-5 bytes thanks to mazzy

param($n)$x=,'X'*$n+,'_'*(8-$n)|random -c 8
-join$x[0..2]
$x[3,4]-join$n
-join$x[5..7]

Try it online!

Shuffles a generated string ranging from ________ to XXXXXXXX (replacing from the left). It then slices through it multiple times, inserting $n in the middle, to build the output string. This last part can probably be greatly optimized because each index costs a minimum of 5 bytes.

\$\endgroup\$
  • 1
    \$\begingroup\$ nice. 86 bytes \$\endgroup\$ – mazzy May 24 at 6:09
0
\$\begingroup\$

Ruby, 59 bytes

Returns a list of strings (one for each line).

->n{a=([0]*(8-n)+[1]*n).shuffle;a[4,0]=n;a.join.scan /.../}

Try it online!

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

C (gcc), 81 bytes

f(n,i,j,k){for(j=i=8,k=n;--i+5;putchar(i%4?i-2?rand()%j--<k?k--,88:95:48+n:10));}

Try it online!

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

Perl 5 -pa, 105 101 bytes

@o=grep!/^....1/&&y/1//=="@F",map{sprintf"%09b",$_}0..2**9-1;$_=$o[rand@o];s/....\K./@F/;s/...\K/\n/g

Try it online!

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

05AB1E, 12 bytes

$×8j.r2äIý3ô

Uses 0 for mines, spaces for blank squares. Outputs a list of lines, which is pretty printed in the TIOs below by joining with newline delimiter (»).

Try it online or verify a few more test cases at once.

Explanation:

$             # Push 0 and the input-digit
 ×            # Repeat the 0 the input-digit amount of times as string
              #  i.e. 4 → "0000"
  8j          # Prepend spaces to make the size 8
              #  → "    0000"
    .r        # Randomly shuffle the characters in this string
              #  i.e. "    0000" → " 00 0  0"
      2ä      # Split it into two equal halves (of 4 characters)
              #  → [" 00 ","0  0"]
        Iý    # Join it with the input-digit
              #  → " 00 40  0"
          3ô  # And then split it into (three) parts of 3 characters
              #  → [" 00"," 40","  0"]
              # (which is output implicitly as result)

12 bytes alternative:

8L@.rIš5._3ô

Uses 1 for mines, 0 for blank squares. Outputs a matrix of digits, which is pretty printed in the TIOs below by joining each row, and then these rows with newline delimiter ().

Try it online or verify a few more test cases at once.

Explanation:

8L            # Push the list [1,2,3,4,5,6,7,8]
  @           # Check for each if the (implicit) input-integer is >= it
              # (1 if truthy; 0 if falsey)
              #  i.e. 4 → [1,1,1,1,0,0,0,0]
   .r         # Randomly shuffle this list
              #  i.e. [1,1,1,1,0,0,0,0] → [0,1,1,0,1,0,0,1]
     Iš       # Prepend the input-digit to the list
              #  → [4,0,1,1,0,1,0,0,1]
       5._    # Rotate the list five times towards the left
              #  → [1,0,0,1,4,0,1,1,0]
          3ô  # And then split it into (three) parts of 3 digits each
              #  → [[1,0,0],[1,4,0],[1,1,0]]
              # (which is output implicitly as result)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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