# Minesweeper

#### Dason

Hey. I got bored so I wrote a minesweeper clone in R. If you run the following script then you can play the game by running
Code:
play.mines.graphic()
play.mines.graphic() is the last line of the script so if you don't want to play right away don't copy the entire thing. If you're truly on a console only system you can even enjoy the fun by running play.mines() - it's not as nice and it's very unpolished but you can still enjoy it.

I considered adding a license but it's really not that complicated and I don't really think anybody would use this in any commercial software. If you really want to copy it and take credit for it I guess you could but that'd be pretty low. Feel free to post it somewhere else if you want but I would appreciate if you give me credit and link to this post.

I'm open to suggestions and feel free to modify it to your liking. Due to limitations of interacting with plots in R you can't place flags. If you click on a mine the game ends. To win you need to clear all locations that are not mines.

I have plans on shading the background of the covered locations to some sort of a gray so they stick out some more. I also wouldn't mind adding some sort of popup after you finish a game asking if you want to replay or stop. I'd also like to add some sort of timer and maybe a high scores list (even if it is just a temporary high scores list during the session) which will be easy to do but I just thought of it and things don't get added instantly. Another thing to add would be difficulty levels. You can essentially mimic those right now by choosing the number of rows, columns, and # of mines correctly but it might be easier for the user to just have a difficulty parameter that accepted something like "easy", "medium", or "hard".

Let me know what you think.

The script:
Code:
## Create a map with mines placed in it
generate.map <- function(n = 8, m = 8, n.mines = 10){
map <- matrix(F, nrow = n, ncol = m)
mines <- sample(1:(n*m), n.mines)
mine.col <- (mines-1) %/% m + 1
mine.row <- mines %% n + 1
for(i in 1:n.mines){
map[mine.col[i], mine.row[i]] <- TRUE
}
return(map)
}

## Let Inf represent that location is a mine
get.nums <- function(row, col, map){
n.row <- dim(map)[1]
n.col <- dim(map)[2]

## Inf represents that location is a mine
if(map[row, col]){
return(Inf)
}

ans <- data.frame(row = c(rep(row-1, 3), rep(row, 2), rep(row+1, 3)),
col = c(col-1, col, col+1, col-1, col+1, col-1, col, col+1),
check = rep(TRUE, 8),
mine = rep(FALSE, 8))
## Find the spots outside of the map
idx <- which(ans$row < 1 | ans$row > n.row | ans$col < 1 | ans$col > n.col)
ans$check[idx] <- FALSE ## Check to see which surrounding areas have mines for(i in 1:8){ if(ans$check[i]){
ans$mine[i] <- map[ans$row[i], ans$col[i]] } } ## Return the number of mines in surrounding areas return(sum(ans$mine))
}

## I don't think I actually use this
## for anything other than testing...
create.num.table <- function(map){
n.row <- dim(map)[1]
n.col <- dim(map)[2]
table <- matrix(0, n.row, n.col)
for(i in 1:n.row){
for(j in 1:n.col){
table[i, j] <- get.nums(i, j, map)
}
}
return(table)
}

## Return a list with modified player.table
## and a boolean indicating if they lost or not.
guess <- function(row, col, player.table, map){

## Assume that the guess doesn't kill the player
cont <- TRUE

## Make the list that we'll return if we don't
## need to do anything
tmplist <- list(player.table = player.table, cont = cont)

## If the spot isn't in the table then do nothing
if(!in.table(row, col, player.table)){
return(tmplist)
}

## If the spot has already been checked then do nothing
if(!is.na(player.table[row, col])){
return(tmplist)
}

## Check what the value is of the guess
tmp <- get.nums(row, col, map)
player.table[row, col] <- tmp

## If you hit a mine don't continue
if(tmp == Inf){
cont <- FALSE
return(list(player.table = player.table, cont = cont))
}

## Clear all cells you could figure out
## if the guess had 0 surrounding mines
## There might be more efficient ways to do this
## but it works.
if(tmp == 0){
player.table <- guess(row-1, col-1, player.table, map)$player.table player.table <- guess(row-1, col, player.table, map)$player.table
player.table <- guess(row-1, col+1, player.table, map)$player.table player.table <- guess(row, col-1, player.table, map)$player.table
player.table <- guess(row, col+1, player.table, map)$player.table player.table <- guess(row+1, col-1, player.table, map)$player.table
player.table <- guess(row+1, col, player.table, map)$player.table player.table <- guess(row+1, col+1, player.table, map)$player.table
}

return(list(player.table = player.table, cont = cont))
}

## Checks if a cell is in a given table
in.table <- function(row, col, player.table){
nrow <- dim(player.table)[1]
ncol <- dim(player.table)[2]
ans <- (row >= 1) & (row <= nrow) & (col >= 1) & (col <= ncol)
return(ans)
}

## Figure out if the table won
check.win <- function(player.table, map){
## You can only win if the number of NAs in
## the player table is the same as the number
## of mines.
if(sum(is.na(player.table)) == sum(map)){
return(TRUE)
}
# Else
return(FALSE)
}

## A console version where you input your guess
## for the row number and column number...
##
## Currently doesn't check to make sure
## the input is valid.
play.mines <- function(n = 8, m = 8, n.mines = 10){
player.table <- matrix(NA, n, m)
map <- generate.map(n, m, n.mines)
cont <- TRUE
while(cont){
win <- check.win(player.table, map)
if(win){
print("==============================")
print("Winner!")
break;
}
print(player.table)
cat("Row Guess: ")
cat("Col Guess: ")
row <- as.numeric(row)
col <- as.numeric(col)
tmp <- guess(row, col, player.table, map)
player.table <- tmp$player.table cont <- tmp$cont
}
print(player.table)
print("==============================")
invisible(NULL)
}

display.table <- function(player.table, nmines = 10, map){
nrow <- dim(player.table)[1]
ncol <- dim(player.table)[2]
spots <- expand.grid(0:(nrow+1), 0:(ncol+1))
win <- check.win(player.table, map)
spotsleft <- sum(is.na(player.table)) - nmines
messg <- paste("Spots left:", spotsleft, "--- # of Mines: ", nmines)
if(win){
messg <- "Winner!"
}

plot(spots,
main = messg,
type = "n",
xlim = c(0.5, nrow+0.5),
ylim = c(ncol+0.5, 0.5),
axes = FALSE,
xlab = "",
ylab = "")

##box()
##axis(1, at = 1:ncol, labels = 1:ncol)
##axis(2, at = 1:nrow, labels = 1:nrow)
plot.colors <- rep("blue", nrow*ncol)
truespots <- expand.grid(1:(nrow), 1:(ncol))
displaytext <- as.character(t(player.table))
plot.colors[which(displaytext == "Inf")] <- "red"
displaytext[which(displaytext == "Inf")] <- "BOOM"
plot.colors[is.na(displaytext)] <- "black"
displaytext[is.na(displaytext)] <- "X"
text(x = truespots[,1], y = truespots[,2], labels = displaytext, col = plot.colors)
for(i in seq(0.5, ncol+.5, 1)){
lines(c(i,i), c(0.5, nrow+0.5))
}
for(i in seq(0.5, nrow + .5, 1)){
lines(c(0.5, ncol+0.5), c(i,i))
}
}

play.mines.graphic <- function(n = 8, m = 8, n.mines = 10){
player.table <- matrix(NA, n, m)
map <- generate.map(n, m, n.mines)
cont <- TRUE
truespots <- expand.grid(1:(n), 1:(m))
while(cont){
win <- check.win(player.table, map)
if(win){
##print("==============================")
print("Winner!")
break;
}
## Display the table using the plot
display.table(player.table, n.mines, map)
## Can only click. No flag functionality.
## This grabs what spot you wanted to click
spot <- identify(x = truespots[,1], y = truespots[,2], plot = FALSE, n = 1)

## Looks like we're setting the guess
## for row and column to be switched but this has to do
## with the way display table works.
row <- truespots[spot,2]
col <- truespots[spot,1]
tmp <- guess(row, col, player.table, map)
player.table <- tmp$player.table cont <- tmp$cont
if(!cont){
print("Lost")
}
}

display.table(player.table, n.mines, map)
invisible(NULL)
}

## To play
play.mines.graphic(n = 8, m = 8, n.mines = 10)
Edit: I've tested on Linux and on my Mac but I haven't gotten around to testing it on windows. Hopefully it works there too? I don't know why it wouldn't unless 'identify' works differently...

Edit 2: I logged onto one of the university servers and it seems to work fine on Windows.

Last edited:

#### Lazar

##### Phineas Packard
oh Very clever! Already played a few rounds.

Last edited:

#### TheEcologist

##### Global Moderator
Edit 2: I logged onto one of the university servers and it seems to work fine on Windows.
Well done, I'm impressed and it works fine on R (64) Windows 7 (in a virtual box - although there is an irritating ping every time you click ;-) ).

I was thinking about making a (2d - 3d) battleship clone in R for a class because you can set up an AI that uses some of the more famous optimization algorithms and it gives you insight into optimized sampling. However, the class is done now and I still haven't found the time :-(

#### Dason

Hmm. I guess I had my computers muted or it doesn't occur on some of them. Anywho I think adding the following line will get rid of the beep
Code:
options(locatorBell = FALSE)

#### Dason

I've updated the code a little bit. There were actually a few bugs in the code so if you tried to play with a non-square board things got messed up. I fixed those and added a timer. I also added the gray scaling I was talking about but it adds quite a bit of overhead so only use it if you have a decently powered machine and are playing on a small board. Also added the ability to just specify a difficulty level instead of having to specify the board size and what not. I attached the code in a .txt file. It's just an R script though.

Examples on how to use the new format:
Code:
## Play with low graphics on beginner is default
play.mines.graphic()

## Set a different difficulty level
play.mines.graphic(difficulty = "intermediate")
play.mines.graphic(difficulty = "expert")
play.mines.graphic(difficulty = "custom", n = 13, m = 12, n.mines = 42)

## Play on beginner with 'high' graphics
play.mines.graphic(difficulty = "beginner", graphic = "high")
If I get bored enough some other day I might update this to use Gtk or maybe Qt so that it's even better. I can already think of a few simple extensions I could do using gWidgets just to allow the user to have a restart button, input boxes to choose difficulty and/or size of the board, high score listing... It wouldn't be too bad but I would probably just want to go all out and learn more about RGtk2 and create a full functionality clone with the ability to detect right clicks to set flags and what not.

Last edited:

#### BGM

##### TS Contributor
Thanks Dason. Minesweeper is one of my favorite game.

#### Dason

Any suggestions for simple things I should implement?

Edit: Note to self - change check.win to this
Code:
## Figure out if the table won
check.win <- function(player.table, map){
## You can only win if the number of NAs in
## the player table is the same as the number
## of mines. Unless it's the last one...
if((sum(is.na(player.table)) == sum(map)) & (!sum(player.table == Inf, na.rm = TRUE))){
return(TRUE)
}
# Else
return(FALSE)
}

## And to increase the speed of graphic = "high" slightly...
## Use rect instead of polygon

## Shades in unknown locations to gray
draw.squares <- function(spots, squares, col = "gray"){
for(i in which(squares)){
j <- spots[i,]
rect(j[1] - 0.5, # xleft
j[2] - 0.5, # ybottom
j[1] + 0.5, # xright
j[2] + 0.5, # ytop
col = col)
}
}

Last edited:

#### Dason

I was thinking about making a (2d - 3d) battleship clone in R for a class because you can set up an AI that uses some of the more famous optimization algorithms and it gives you insight into optimized sampling. However, the class is done now and I still haven't found the time :-(
You should totally implement that. Maybe if we made enough games we could package them together and submit it to CRAN.

Aww heck once I get this minesweeper clone good enough I might just package that together for the heck of it. Are there any packages on CRAN that just provide games?

#### trinker

##### ggplot2orBust
:tup:It always makes me laugh when someone takes a sophisticated tool and inevitably uses it to play games. I can remember in my youth spending more time making my TI 81 play games then working on my calculus. This is very impressive. I’ve already enjoyed a few rounds.:wave:

#### TheEcologist

##### Global Moderator
You should totally implement that. Maybe if we made enough games we could package them together and submit it to CRAN.

Aww heck once I get this minesweeper clone good enough I might just package that together for the heck of it. Are there any packages on CRAN that just provide games?
Dason, that is a collaboration I would like to take part in! Lets do it!

#### quark

If you guys ever need a games site/blog/host, I can help. Rock on.

#### TheEcologist

##### Global Moderator
:tup:It always makes me laugh when someone takes a sophisticated tool and inevitably uses it to play games. I can remember in my youth spending more time making my TI 81 play games then working on my calculus. This is very impressive. I’ve already enjoyed a few rounds.:wave:
That is how great things happen! One story I heard is that a few guys ( Ken Thompson, Dennis Ritchie, Brian Kernighan) were bored during night shifts so they sought a way to play some games. This later became "UNIX".

#### TheEcologist

##### Global Moderator
If you guys ever need a games site/blog/host, I can help. Rock on.
Haha thanks quark.. lets get some games first! Who is going to make tic tac toe? I've started on battleship

#### Dason

Any progress on battleship? What kind of an interface were you planning on using?

I recently upgraded the minesweeper game to use gWidgets and the RGtk2 libraries. This turns out to be pretty nice. My main issue right now is getting colors to display in my labels. I was able to get it somewhat working using gtext instead of glabel but that took too long at each click. I might be able to premake all of the 'labels' that I need but I haven't tried that yet and don't know how long that would add to the load up time.

TheEcologist have you ever used git? I'm thinking of possibly making a repository for the collaboration.

#### TheEcologist

##### Global Moderator
Any progress on battleship? What kind of an interface were you planning on using?

I recently upgraded the minesweeper game to use gWidgets and the RGtk2 libraries. This turns out to be pretty nice. My main issue right now is getting colors to display in my labels. I was able to get it somewhat working using gtext instead of glabel but that took too long at each click. I might be able to premake all of the 'labels' that I need but I haven't tried that yet and don't know how long that would add to the load up time.

TheEcologist have you ever used git? I'm thinking of possibly making a repository for the collaboration.
I started work on it, I liked your graphical interface so I am going to use that however I'm working on an important paper revision now - but I promise to get back to you soon.

#### Dason

No worries. I just worked on the new interface today which made me think of this thread so I was just checking. Have you ever used git though?

#### Dason

I pretty much have the version using gWidgets (gWidgetsRGtk2 actually...) finished up. It's pretty nice and actually handles a lot better than the previous version using the plotting device (but no surprise there really). At the moment it has color support for the numbers. You can set flags through the use of right clicking. And at the end it tells you how long it took you to complete.

I want to add a few things before releasing any code - mainly a flag count, an automatic clock so you know how long you've taken so far, and a slightly better interface for choosing your difficulty and starting a new game. As it is right now you have to use the command line every time you want to play another game because the mines window closes when you win or lose. I'll probably just add a reset button somewhere on the interface to take care of that and have some file menus to take care of difficulty levels.

Does anybody have/use gWidgets and would be willing to be an alpha tester?

#### bryangoodrich

##### Probably A Mammal
(1) You have WAY too much time on your hands!

(2) Awesome! I just became a winner Now I gotta go analyze your code to see the details of this nice little creation of yours.

#### Dason

(1) You have WAY too much time on your hands!

(2) Awesome! I just became a winner Now I gotta go analyze your code to see the details of this nice little creation of yours.
I suppose you're playing the old version on the plotting device. The new version with gWidgets is quite a bit nicer ;-)

I just gotta tweak some things. But like I said if you're interested in alpha testing just let me know. I don't have access to a windows machine right now so I'd be interested in how it works there.

#### vinux

##### Dark Knight
Nice Dason. There should be a button for awesomeness . I tried a few game stuff in Open GL. that doesn't match in this forum.

Quark may say " There is no b button for awesomeness... or attractiveness" . ( I guess you ppl watched Kungfu panda)