18
\$\begingroup\$

Everyone knows the old minesweeper game that shipped with Windows XP. It's a simple grid with a 9x9 matrix of cells containing either a number (indicating how many mines are adjacent to it) or a mine.

enter image description here

The challenge is to generate a random 9x9 grid with 10 bombs given any integer seed (up to whatever your machine/language's largest int is) with brownie points if you implement the PRNG yourself

example output: cells contain either numerals 0-8 or * for mines

*101*1000
110111000
123210000
1***10000
123210011
00000002*
00000114*
000112*3*
0001*2121

Shortest code in bytes wins.. standard rules etc, etc..

\$\endgroup\$
  • 3
    \$\begingroup\$ You should indicate what the numbers mean :) \$\endgroup\$ – Nathan Merrill Sep 2 '16 at 20:11
  • 4
    \$\begingroup\$ Microsoft Minesweeper is a heck of a lot older than XP and minesweeper-like games date back to at least the 60s. \$\endgroup\$ – AdmBorkBork Sep 2 '16 at 20:19
  • 11
    \$\begingroup\$ Also, I don't have time to play Minesweeper while at work -- I'm too busy on PPCG. ;-) \$\endgroup\$ – AdmBorkBork Sep 2 '16 at 20:41
  • 1
    \$\begingroup\$ What counts as a PRNG, exactly? How many different configurations must it be able to produce? Can we not use the seed and just generate a different configuration each time, if our language has a PRNG which is automatically initallized to a "random" seed? \$\endgroup\$ – Luis Mendo Sep 2 '16 at 21:07
  • 1
    \$\begingroup\$ @TimmyD But XP's version is the first version that had a 9x9 grid. Anything older uses an 8x8 grid for Beginner. #outnerded ;) \$\endgroup\$ – mbomb007 Sep 2 '16 at 21:37
3
\$\begingroup\$

Dyalog APL, 40 bytes

⎕rl←1⋄(1,¨a)⍕¨{⍉3+/0,⍵,0}⍣2⊢a←9 9⍴9≥?⍨81

(assumes ⎕io←0)

the 1 in ⎕rl←1 is the seed

from right to left:

?⍨81 is the same as 81?81 - a random permutation

9≥ results in a bitmask containing ten 1s at random positions, the rest are 0s

a←9 9⍴ reshape to a 9-by-9 square and call it "a"

{ }⍣2 do the following twice:

⍉3+/0,⍵,0 sliding window sum of 3 columns (assume 0s outside), then transpose

(1,¨a)⍕¨ is format (convert to string) each. The left argument to specifies the total number of characters and fractional characters in the result. If can't format according to that spec it outputs a * - a lucky coincidence for this problem. a will be 1 where the mines are - trying to fit a whole and fractional part into a single char is impossible, so those will appear as *s.

\$\endgroup\$
  • \$\begingroup\$ Can you explain the ⎕io←0 assumption? I'm not familiar with Dyalog APL... \$\endgroup\$ – Aaron Apr 10 '17 at 13:44
  • 1
    \$\begingroup\$ Array indices in Dyalog are 1-based by default. Setting ⎕io (the "Index Origin") to 0 makes them 0-based and changes some primitives accordingly, e.g. ⍳3 will be 0 1 2, not 1 2 3. That can be done either programmatically (⎕io←0) or from the preferences in the GUI. Having this choice is a 50-year-old mistake that still splits the tiny APL community of today. \$\endgroup\$ – ngn Apr 10 '17 at 14:30
5
\$\begingroup\$

MATLAB, 94 93 bytes

rng(input(''));x(9,9)=~1;x(randperm(81,10))=1;y=[conv2(+x,ones(3),'s')+48 ''];y(x)=42;disp(y)

Example run (the first line after the code is the input typed by the user):

>> rng(input(''));x(9,9)=~1;x(randperm(81,10))=1;y=[conv2(+x,ones(3),'s')+48 ''];y(x)=42;disp(y)
99
*10001*2*
220001232
*201111*1
*312*1111
12*211000
011211000
0001*1000
000112110
000001*10

Explanation

rng(input(''));

takes an integer and uses it as seed. (This works in modern MATLAB versions. Old versions may need a different syntax.)

x(9,9)=~1;

assigns logical 0, or false (obtained by logically negating 1) to the entry (9,9) of a matrix x. The rest of the entries are automatically initiallized to logical 0 too.

x(randperm(81,10))=1; 

assigns 1 (autoomatically cast to logical 1, or true) to 10 of the 81 entries of x, chosen randomly without replacement. These entries are the ones that contain bombs.

conv2(+x,ones(3),'s')

is an abbreviation of conv2(+x,ones(3),'same'). It convolves the matrix x (which needs to be cast to double, using +) with a 3×3 neighbourhood containing 1. This counts how many bombs are adjacent to each entry. For entries that contain a bomb it includes that bomb, but the value there will be overwritten later.

y=[...+48 ''];

adds 48 to the value, to convert from number to ASCII code. Concatenating with the empty matrix casts these ASCII codes to chars.

y(x)=42;

assigns 42 (ASCII code for '*') to the positions of the bombs. These positions are given by x, which is here used as a logical index.

disp(y)

displays the result.

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

Javascript (ES6), 204 or 198 bytes

Custom PRNG (204 bytes)

s=>(p=-1,S=n=>(x=p%9-(n+=p)%9)*x-64&&b[n]=='*',T=n=>S(n)+S(-n),b=[...'*00000000'.repeat(9)]).sort(_=>(s=(22695477*s+1)>>>0)&1||-1).map(c=>(p++,c=='0'?T(1)+T(8)+T(9)+T(10):c)).join``.match(/.{9}/g).join`
`

This code is using a linear congruential generator with multiplier 22695477 and increment 1 (this is the Borland C/C++ implementation).

Due to the poor efficiency of the PRNG during its warmup phase, I had to place one bomb per row (instead of 10 at the beginning or 10 at the end of the unshuffled array). So, there are only 9 bombs. I may try to fix that later.

Also, there must be a simpler/shorter way of processing the 'out of board' check (x=p%9-(n+=p)%9)*x-64 but I just can't figure it out right now.

Using Math.random() (198 bytes)

s=>(p=-1,S=n=>(x=p%9-(n+=p)%9)*x-64&&b[n]=='*',T=n=>S(n)+S(-n),b=[...'**********'+'0'.repeat(71)]).sort(_=>Math.random()-.5).map(c=>(p++,c=='0'?T(1)+T(8)+T(9)+T(10):c)).join``.match(/.{9}/g).join`
`

This one includes 10 mines as requested.

Demo

let f =
_=>(p=-1,S=n=>(x=p%9-(n+=p)%9)*x-64&&b[n]=='*',T=n=>S(n)+S(-n),b=[...'**********'+'0'.repeat(71)]).sort(_=>Math.random()-.5).map(c=>(p++,c=='0'?T(1)+T(8)+T(9)+T(10):c)).join``.match(/.{9}/g).join`
`
console.log(f())

\$\endgroup\$
  • \$\begingroup\$ '**********'+'0' is equal to '**********'+0; that saves two bytes on the 198-byte-version. \$\endgroup\$ – Paul Schmitz Sep 3 '16 at 12:42
  • \$\begingroup\$ @PaulSchmitz - Unfortunately this '0' is supposed to be repeated and 0.repeat() wouldn't work. \$\endgroup\$ – Arnauld Sep 3 '16 at 13:58
  • \$\begingroup\$ Oops, I though it would get executed like ...('**********'+0).repeat(71). Sorry. \$\endgroup\$ – Paul Schmitz Sep 3 '16 at 14:40
3
\$\begingroup\$

Python 2, 269 266 264 bytes

from random import*
seed(input())
z=1,0,-1
n=range(9)
m=[[0]*9 for _ in n]
for x,y in sample([[x,y]for x in n for y in n],10):
 m[x][y]=-9
 for a in z:
  for b in z:
    if 0<=x+a<9>0<=y+b<9:m[x+a][y+b]+=1 # it gets displayed as 4 spaces, but the beginning of this line is a single tab
print("\n".join("".join([`c`,'*'][c<0]for c in l)for l in m))

Try it on ideone.com

Saved 2 bytes thanks to Aaron.

Most likely still golfable.

Explanation

random is imported for using seed to seed the PRNG and sample to select ten bomb locations randomly. m is a 9 x 9 matrix saving the board. For each of the bomb locations, the corresponding entry in m gets set to -9 and all neighbouring entries get incremented. This way m ends up containing the count of adjacent bombs for non-bomb cells and a negative number for bomb cells. The final print prints the whole board by iterating through all lines l in m and all cells c in l.

\$\endgroup\$
  • \$\begingroup\$ What exactly is 'random' used for, exactly? \$\endgroup\$ – Qwerp-Derp Sep 2 '16 at 22:13
  • \$\begingroup\$ @Qwerp-Derp probably to seed the random number generator indirectly used by sample() \$\endgroup\$ – Patrick Roberts Sep 2 '16 at 23:10
  • \$\begingroup\$ save 2 bytes by mixing tab indents inside for a in z: block (only python 2.x) \$\endgroup\$ – Aaron Apr 7 '17 at 14:57
3
\$\begingroup\$

R, 187 Bytes

set.seed();x=1:121;y=x[!(x%%11 %in% 0:1|(x-1)%/%11 %in% c(0,10))];z=sample(y,10);x=x*0;for(t in z){p=t+c(-10:-12,-1,1,10:12);x[p]=x[p]+1};x[z]=9;m=data.frame(matrix(x[y],9));m[m==9]='*';m

Try it on Ideone

Explanation:

set.seed() take a cst seed.

x is the index for a 11*11 matrix

y is the index of the 9*9 matrix in the 11*11 matrix

z is the index of the bomb

x=x*0 initialise the matrix value

The loop add 1 to x in case of adjacent bomb.

\$\endgroup\$
  • 1
    \$\begingroup\$ I think you have to take the argument to set.seed() as input. \$\endgroup\$ – BLT Apr 8 '17 at 3:51
2
\$\begingroup\$

JavaScript ES6, 244 bytes

f=(a=[...Array(11)].map(_=>Array(11).fill(0)),n=10,r=_=>Math.random()*9|0,x=r(),y=r())=>a[x+1][y+1]>8||[0,1,2].map(i=>[0,1,2].map(j=>a[x+i][y+j]++),a[x+1][y+1]=9)&&--n?f(a,n):a.slice(1,-1).map(a=>a.slice(1,-1).map(n=>n<9?n:`*`).join``).join`
`
;o.textContent=f()
<pre id=o>

\$\endgroup\$
  • \$\begingroup\$ You may want to elaborate on which part is your code. \$\endgroup\$ – NoOneIsHere Sep 2 '16 at 23:49
  • \$\begingroup\$ @NoOneIsHere The first 244 bytes, hopefully ;-) The first line should be 242 bytes long, then there's the newline and the ` character. \$\endgroup\$ – Neil Sep 3 '16 at 0:10
1
\$\begingroup\$

Ruby, 181 194 183+1 = 184 bytes

Forgot to actually set the seed, whoops. Uses the -n flag.

Try it online!

srand$_.to_i
a=[0]*81
[*0..80].sample(10).map{|i|w=i%9;h=i/9;a[i]=-99
(r=-1..1).map{|x|x+=w
x<0||x>8?0:r.map{|y|y+=h
y<0||y>8?0:a[9*y+x]+=1}}}
puts a.map{|c|c<0??*:c}.join.scan /.{9}/
\$\endgroup\$
0
\$\begingroup\$

Python 2, 172 bytes

from random import*
seed(input())
r=range
b=set(sample(r(81),10))
for j in r(9):print''.join([[`len({x-10,x-9,x-8,x-1,x+1,x+8,x+9,x+10}&b)`,'*'][x in b]for x in r(j,81,9)])

Try it online!

\$\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.