# Working Minesweeper

Similar to generating minesweeper grids, although the challenge is to make a working minesweeper grid. This will be longer code than normal (I think).

Minesweeper is a logic game found on most OS's. The goal of the game is to determine where the mines are on a grid, given numbers indicating the number of mines around that spot.

Required features:

-Randomized mine generation
-8x8 field with 10 mines
-Mine and "unknown" flags
-Reveal nearby blank spaces when a blank space has been revealed.
-Input and output code: It must be playable.  (Input and output code counts in the total)


Note on scoring:

Anything that is needed to make the program work is counted.
If it can be deleted and not affect the program, get rid of it.
I will occasionally update the selected answer to shorter programs if needed.


I came across a more specific version of this problem in computer science class: make a working version with the shortest number of lines in visual basic (I got 57 lines), and I thought it will be an interesting challenge for code golf. If there are any suggestions for improving the question, please comment. Shortest code in bytes wins.

• Do we need to allow for mine and "unknown" flags? Also, does UI code count towards the total? – Shmiddty Feb 6 '13 at 17:05
• Also, I assume we're counting bytes instead of lines, since several languages could make this as a one-liner. – Shmiddty Feb 6 '13 at 17:12
• Edited original post to clarify uncertainties. – EAKAE Feb 6 '13 at 20:09
• I edited the title, cause I first thought you're looking for solutions in functional programming languages only. I renamed to 'working' instead of 'functional', while it is quiete normal, that we look for working solutions - what else? – user unknown Feb 7 '13 at 23:11

# Python 2.7 (487C)

"""
char meaning:
'?': unknown flag
'!': mine flag
'x': default
how to play:
Input 3 chars each time. The first char is the action
and the rest form a position. For example, '013' means
uncover grid (1,3), '110' means flag the grid (1,0).

The top-left corner is (0, 0), bottom-left (7,0), etc.

Player will lose after uncover a mine, the program will
output "Bom". If the Player uncovers all grid that do
not contain a mine, he wins and the program will output
"Win".
"""
import random as Z
S=sum
M=map
T=range
P=[(i,j)for i in T(8)for j in T(8)]
C=dict(zip(T(-3,9),'?!x012345678'))
m={p:-1 for p in P}
h=Z.sample(P,10)
def U(p):
if m[p]>=0:return 0
n=filter(lambda(c,d):0<max(abs(p[0]-c),abs(p[1]-d))<2,P)
m[p]=s=S((x in h)for x in n)
return(1 if s else S(M(U,n))+1,-1)[p in h]
s=u=0
while(s<54)&(u>-1):
f,i,j=M(int,raw_input(''.join((C[m[x]]+'\n '[x[1]<7])for x in P)))
p=i,j;c=m[p]
if f*(c<0):m[p]=-1-(-c)%3
else:u=U(p);s+=u
print'WBionm'[s<54::2]


Full game experience:

x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
x x x x x x x x
000
0 0 1 x x x x x
0 0 2 x x x x x
0 0 2 x x x x x
0 0 1 2 x x x x
0 0 0 1 x x x x
1 1 0 2 x x x x
x 1 0 2 x x x x
x 1 0 1 x x x x
070
0 0 1 x x x x x
0 0 2 x x x x x
0 0 2 x x x x x
0 0 1 2 x x x x
0 0 0 1 x x x x
1 1 0 2 x x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
123
0 0 1 x x x x x
0 0 2 x x x x x
0 0 2 ! x x x x
0 0 1 2 x x x x
0 0 0 1 x x x x
1 1 0 2 x x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
113
0 0 1 x x x x x
0 0 2 ! x x x x
0 0 2 ! x x x x
0 0 1 2 x x x x
0 0 0 1 x x x x
1 1 0 2 x x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
003
0 0 1 1 x x x x
0 0 2 ! x x x x
0 0 2 ! x x x x
0 0 1 2 x x x x
0 0 0 1 x x x x
1 1 0 2 x x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
004
0 0 1 1 1 x x x
0 0 2 ! x x x x
0 0 2 ! x x x x
0 0 1 2 x x x x
0 0 0 1 x x x x
1 1 0 2 x x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
014
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! x x x x
0 0 1 2 x x x x
0 0 0 1 x x x x
1 1 0 2 x x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
154
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! x x x x
0 0 1 2 x x x x
0 0 0 1 x x x x
1 1 0 2 ! x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
044
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! x x x x
0 0 1 2 x x x x
0 0 0 1 1 x x x
1 1 0 2 ! x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
034
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! x x x x
0 0 1 2 3 x x x
0 0 0 1 1 x x x
1 1 0 2 ! x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
035
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! x x x x
0 0 1 2 3 3 x x
0 0 0 1 1 x x x
1 1 0 2 ! x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
045
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! x x x x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! x x x
x 1 0 2 x x x x
1 1 0 1 x x x x
055
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! x x x x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 x x x x
1 1 0 1 x x x x
124
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! ! x x x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 x x x x
1 1 0 1 x x x x
164
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! ! x x x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 ! x x x
1 1 0 1 x x x x
174
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! ! x x x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 ! x x x
1 1 0 1 ! x x x
074
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! ! x x x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 ! x x x
1 1 0 1 1 x x x
125
0 0 1 1 1 x x x
0 0 2 ! 4 x x x
0 0 2 ! ! ! x x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 ! x x x
1 1 0 1 1 x x x
005
0 0 1 1 1 1 x x
0 0 2 ! 4 x x x
0 0 2 ! ! ! x x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 ! x x x
1 1 0 1 1 x x x
015
0 0 1 1 1 1 x x
0 0 2 ! 4 4 x x
0 0 2 ! ! ! x x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 ! x x x
1 1 0 1 1 x x x
126
0 0 1 1 1 1 x x
0 0 2 ! 4 4 x x
0 0 2 ! ! ! ! x
0 0 1 2 3 3 x x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 ! x x x
1 1 0 1 1 x x x
036
0 0 1 1 1 1 x x
0 0 2 ! 4 4 x x
0 0 2 ! ! ! ! x
0 0 1 2 3 3 3 x
0 0 0 1 1 1 x x
1 1 0 2 ! 2 x x
x 1 0 2 ! x x x
1 1 0 1 1 x x x
046
0 0 1 1 1 1 x x
0 0 2 ! 4 4 x x
0 0 2 ! ! ! ! x
0 0 1 2 3 3 3 2
0 0 0 1 1 1 0 0
1 1 0 2 ! 2 0 0
x 1 0 2 ! 2 0 0
1 1 0 1 1 1 0 0
127
0 0 1 1 1 1 x x
0 0 2 ! 4 4 x x
0 0 2 ! ! ! ! !
0 0 1 2 3 3 3 2
0 0 0 1 1 1 0 0
1 1 0 2 ! 2 0 0
x 1 0 2 ! 2 0 0
1 1 0 1 1 1 0 0
007
0 0 1 1 1 1 x 1
0 0 2 ! 4 4 x x
0 0 2 ! ! ! ! !
0 0 1 2 3 3 3 2
0 0 0 1 1 1 0 0
1 1 0 2 ! 2 0 0
x 1 0 2 ! 2 0 0
1 1 0 1 1 1 0 0
017
0 0 1 1 1 1 x 1
0 0 2 ! 4 4 x 3
0 0 2 ! ! ! ! !
0 0 1 2 3 3 3 2
0 0 0 1 1 1 0 0
1 1 0 2 ! 2 0 0
x 1 0 2 ! 2 0 0
1 1 0 1 1 1 0 0
016
Win


The last step is dangerous, though.

• This is definitely too old to do anything, but you can remove space in -1 for... and 1 if... to save two bytes. – Zacharý Nov 19 '17 at 23:42
• (note that the score is not counting the documentation and counting the trailing newline) – user202729 Mar 11 '18 at 7:18

## Javascript, 978 bytes (824 without CSS)

Checklist:

Randomized mine generation - yes
8x8 field with 10 mines - yes
Mine flags - Yes
"unknown" flags - no
Reveal nearby blank spaces when a blank space has been revealed. - yes
Input and output code: It must be playable. - yes


JS:

(function(){
f=Math.floor;r=Math.random;b=8,s=[-1,0,1],o='',m='*',l=0;

for(g=[i=b];i;)g[--i]=[0,0,0,0,0,0,0,0];
for(i=10,a=f(r()*64);i--;g[f(a/b)][a%b]=m)while(g[f(a/b)][a%b])a=f(r()*64);
for(i=64;i--;z.id='b'+(63-i),c.appendChild(z))z=document.createElement('button');
for(d=b;d--;)
for(r=b;r--;)
s.map(function(y){
s.map(function(x){
if(g[d][r]!=m&&g[d+y]&&g[d+y][r+x]==m)g[d][r]++;
});
});

c.onclick=function(e){
var t=e.target,
i=t.id.slice(1),
x=i%b,
y=f(i/b),
n=t.className=='b';

if(t.innerHTML||(n&&!e.ctrlKey))return;
if(e.ctrlKey)return t.className=(n?'':'b')

};
function q(x,y){
if(x<0||x>7||y<0||y>7)return;

var p=y*b+x,
v=g[y][x],
t=document.all['b'+p];

if(v!=m&&!t.innerHTML){
t.innerHTML=g[y][x];
t.className='f';
l++;
if(!v){t.className='z';s.map(function(d){s.map(function(r){q(x+r,y+d)})})}
}
return v==m
}
})();


MiniJS 812 bytes:

f=Math.floor;r=Math.random;b=8,s=[-1,0,1],o='',m='*',l=0,h='b';for(g=[i=b];i;)g[--i]=[0,0,0,0,0,0,0,0];for(i=10,a=f(r()*64);i--;g[f(a/b)][a%b]=m)while(g[f(a/b)][a%b])a=f(r()*64);for(i=64;i--;z.id=h+(63-i),c.appendChild(z))z=document.createElement('button');for(d=b;d--;)for(r=b;r--;)s.map(function(y){s.map(function(x){if(g[d][r]!=m&&g[d+y]&&g[d+y][r+x]==m)g[d][r]++})});c.onclick=function(e){var t=e.target,i=t.id.slice(1),n=t.className==h;if(t.innerHTML||(n&&!e.ctrlKey))return;if(e.ctrlKey)return t.className=(n?'':h);if(q(i%b,f(i/b)))alert('boom');if(l==54)alert('win')};function q(x,y){if(x<0||x>7||y<0||y>7)return;var p=y*b+x,v=g[y][x],t=document.all[h+p];if(v!=m&&!t.innerHTML){t.innerHTML=g[y][x];t.className='f';l++;if(!v){t.className='z';s.map(function(d){s.map(function(r){q(x+r,y+d)})})}}return v==m}


HTML 12 bytes

<div id="c">


The CSS isn't necessary from a functionality standpoint, but is from a usability standpoint:

#c{
width:300px;
height:300px;
}
button{
width:12.5%;
height:12.5%;
line-height:30px;
}
.f,.z{
background:#fff;
border:solid 1px #fff;
}
.z{
color:#fff;
}
.b{background:#f00}


Mini CSS 154 bytes:

#c{width:300px;height:300px}button{width:12.5%;height:12.5%;line-height:30px}.f,.z{background:#fff;border:solid 1px #fff}.z{color:#fff}.b{background:#f00}


## C, 568, 557, 537

Checklist:
Randomized mine generation - yes
8x8 field with 10 mines - yes
Mine and "unknown" flags - yes
Reveal nearby blank spaces when a blank space has been revealed. - yes
Input and output code: It must be playable. - yes

Further to playable:
Win detection (found all mines, or revealed all empties)
Bang detection (hit a mine)
Game terminates.

Output format:
# - unrevealed
! - a flagged mine
* - a mine
(number) - number of neighbouring mines
? - unknown flag

Input format:
x y f
- where x is 0..7, y is 0..7 (origin upper-left)
- f is 0 to open up, 1 to flag a mine, and 2 to flag a unknown


example game:

./a.out
5 5 0
# 1 0 0 0 2 # #
# 1 0 0 0 2 # #
# 1 0 0 0 1 1 1
# 1 0 0 0 0 0 0
# # 1 0 0 0 1 1
# # 1 0 0 0 1 #
# # # 1 2 1 # #
# # # # # # # #
6 1 1
# 1 0 0 0 2 # #
# 1 0 0 0 2 ! #
# 1 0 0 0 1 1 1
# 1 0 0 0 0 0 0
# # 1 0 0 0 1 1
# # 1 0 0 0 1 #
# # # 1 2 1 # #
# # # # # # # #
7 5 0
# 1 0 0 0 2 # #
# 1 0 0 0 2 ! #
# 1 0 0 0 1 1 1
# 1 0 0 0 0 0 0
# # 1 0 0 0 1 1
# # 1 0 0 0 1 *
# # # 1 2 1 # 1
# # # # # # # #
bang!


code:

// 8x8 grid but with padding before first row, after last row, and after last column, i.e. its 9x10
m[99]; // 0=empty,1=mine
u[99]; // 0=revealed,1=unrevealed,2=flag,3=unknown

// count neighbouring mines (8way)
c(i){return m[i-8]+m[i-9]+m[i-10]+m[i+8]+m[i+9]+m[i+10]+m[i-1]+m[i+1];}

// reveal (4way)
r(i){
if(u[i]){
u[i]=0;
if(!c(i))r(i-9),r(i+9),r(i+1),r(i-1);
}
}

i,x,y,f,e;
main(){
// place 10 mines
for(srand(time(0));i<10;){
x=rand()%64;
x+=9+x/8;
if(!m[x]){
m[x]=1;
i++;
}
}
for(;y<64;y++)u[y+9+y/8]=1; // mark visible grid as being unrevealed

while(!e){
// read input 0..7 0..7 0..2
scanf("%d%d%d",&x,&y,&f);
i=x+9+y*9;
if(f)u[i]=f==1?2:u[i]==3?1:3;else r(i); // flag, toggle unknown/unrevealed, open

// show grid and calc score
for(y=f=x=0;x<64;x++){
i=x+9+x/8;
putchar(u[i]?" #!?"[u[i]]:m[i]?42:48+c(i)); // 42='*', 48='0'
putchar(x%8==7?10:32);
if(!u[i])y+=m[i]?-99:1;   // y = number of correctly open
if(u[i]==2)f+=m[i]?1:-99; // f = number of correct mines
}
if(y<0||y==54||f==10)e=puts(y<0?"bang!":"win!"); // 54 = 64-10
}
}

• I tried to add the grid padding, but it made my program longer :P Good job. – beary605 Feb 8 '13 at 3:08
• does for(x=64;x--;)... work for c? – Shmiddty Feb 8 '13 at 22:30

# Mathematica 566 548 1056

Edit: This is a complete rewrite. I gave up trying to obtain the shortest code and decided instead to build in the features that made most sense.

r indicates the number of rows in the grid. c indicates the number of columns in the grid. m: number of mines.

The game is played by mouse-clicking on the buttons. If the player clicks on a mine, the cell turns black and the program prints "You Lose!"

The checkbox "u" allows the player to peek at the complete solution at any time. The flags, "?" and "!" can be placed in any cell as desired.

DynamicModule[{s, x, f, l},
Manipulate[
Column[{
Grid[s],
If[u, Grid@f, Null]
}],
Grid[{{Control@{{r, 8}, 4, 16, 1, PopupMenu},
Control@{{c, 8}, 4, 16, 1, PopupMenu},
Control@{{m, 10}, 1, 50, 1, PopupMenu}},
{Button["New", i],
Control@{{e, 0}, {0 -> "play", 1 -> "?", 2 -> "!"}, SetterBar},
Control@{{u, False}, {True, False}}}}],
Deployed -> True,

Initialization :>
(p = ReplacePart;
q = ConstantArray;
z = Yellow;
w = White;
b := Array[Button["  ", v[{#, #2}], Background -> z] &, {r, c}];
a := RandomSample[l = Flatten[Array[List, {r, c}], 1], m];
d[m1_] :=
p[ListConvolve[BoxMatrix@1, p[q[0, {r, c}], (# -> 1) & /@ m1], 2,
0], (# -> "*") & /@ (x)];
n[y_] := Complement[Select[l, ChessboardDistance[y, #] == 1 &], x];
d[m1_] :=
p[ListConvolve[BoxMatrix@1, p[q[0, {r, c}], (# -> 1) & /@ m1], 2,
0], (# -> "*") & /@ (x)];

v[{r_, c_}] :=
Switch[e,
1, If[s[[r, c, 3, 2]] == z,
s = p[s, {{r, c, 1} -> If[s[[r, c, 1]] == "?", "  ", "?"]}],
Null],

2, If[s[[r, c, 3, 2]] == z,
s = p[s, {{r, c, 1} -> If[s[[r, c, 1]] == "!", "  ", "!"]}],
Null],
3, Null,

0, Switch[f[[r, c]],
"*", (Print["You lose!"]; (s = p[s, {r, c, 3, 2} -> Black])),
0, (s = p[s, {{r, c, 1} -> "  ", {r, c, 3, 2} -> w}];
f = p[f, {{r, c} -> ""}]; v /@ n[{r, c}]),
"  ", Null,
_, (s = p[s, {{r, c, 1} -> f[[r, c]], {r, c, 3, 2} -> w}])]];

i :=
(x = a;s = b;f = d[x]);i) ] ]


Initial State

At a later point...

• The 'new' button is probably costing you a bunch of characters. – Shmiddty Feb 8 '13 at 22:33
• And it doesn't look like you have flagging implemented yet. – Shmiddty Feb 8 '13 at 22:34
• I'm not sure what you mean by flagging. Do you mean an option to allow the player to place a question mark on a cell? BTW, the "New button costs about 25 chars". – DavidC Feb 8 '13 at 22:48
• The player should be able to place a "flag" on a square they think is a mine, or a "?" on a square they are uncertain about. – Shmiddty Feb 8 '13 at 22:48
• @Shmiddty Flags are now implemented (along with a few other things). – DavidC Feb 15 '13 at 17:58

## Python (502 566)

Checklist:

Randomized mine generation - yes
8x8 field with 10 mines - yes
Mine and "unknown" flags - yes
Reveal nearby blank spaces when a blank space has been revealed. - yes
Input and output code: It must be playable. - yes


It has a win detector as well.

Input is given while the game is running, with (f, x, y). (x, y) is the coordinates of the grid selection, f is whether you want to flag or not. (0, 0, 0) would open up (0, 0), and (1, 2, 3) would flag (2, 3). Flagging works in a cycle: flagging a square twice gives a question mark.

(number) - number of mines
(space) - unexplored
. - 0 mines
! - flag
" - question

import random
A=[-1,0,1]
R=lambda x:[x+i for i in[-9,-8,-7,-1,1,7,8,9]if(0<x+i<64)&([i,x%8]not in([7,0],[-7,7],[-1,0],[1,7]))]
M=lambda p:sum(G[i]=='*'for i in R(p))
def V(p):
m=M(p);G[p]=mif m else'.'
if m>0:return
for c in R(p):
if' '!=G[c]:continue
m=M(c);G[c]=m
if m==0:G[c]='.';V(c)
G=[' ']*54+['*']*10
random.shuffle(G)
while' 'inG:
for i in range(8):print[j.replace('*',' ')[0]for j in G[8*i:8*i+8]]
i=input()[::-1];a=i[0]*8+i[1];b=G[a]
if i[2]:G[a]=(chr(ord(b[0])+1)if'"'!=b[0]else' ')+b[1:];continue
if'*'==b:print'L';break
if'!'!=b:V(a)


Needs to be improved: function R [get all squares around item p] (101 chars), printing (69 chars), flagging (72 chars)

# Dyalog APL, 113 bytes

{⎕←1 0⍕c+○○h⋄10=+/,h:1⋄m⌷⍨i←⎕:0⋄∇{~⍵⌷h:0⋄(⍵⌷h)←0⋄0=⍵⌷c:∇¨(,⍳⍴m)∩⍵∘+¨,2-⍳3 3⋄0}i}h←=⍨c←{⍉3+/0,⍵,0}⍣2⊢m←8 8⍴10≥?⍨64

non-competing: no "mine" and "unknown" flags

prints * for unopened cells and digits for opened (including 0)

repeatedly asks the user for the 1-based coordinates of a cell to open

ultimately outputs 0 on failure (mine opened) or 1 on success (only 10 unopened left)

looks like this:

********
********
********
********
********
********
********
********
⎕:
1 1
00000000
11012321
*112****
********
********
********
********
********
⎕:
3 8
00000000
11012321
*112***1
********
********
********
********
********
⎕:
4 7
00000000
11012321
*112***1
******3*
********
********
********
********
⎕:


...