#' Creates a new msweepeR board
#'
#' This function creates a new msweepeR board of width \code{w} and height \code{h},
#' with the specified number of mines \code{m}.
#'
#' This function is called with the constructor \code{\link{msweepeR}}, and it's recommended that
#' it's only called through such class constructor.
#'
#' @param w Width of the game board. Must be a positive integer > 3.
#' @param h Height of the game board. Must be a positive integer > 3.
#' @param m Number of mines in the board. Must be a positive integer. Please keep in mind that
#' the number of mines can't be higher than half of the total number of tiles.
#' @return This function returns an R object of class \code{msBoard}. It contains a
#' matrix representing the mines positions in the game board, a matrix representing
#' the mine count in the 8 neighbouring tiles, and a matrix representing the player's
#' uncovered tiles and flags. The \code{msBoard} object also includes some basic info
#' about the game, like the number of turns (moves) playes, whether the player has already
#' opened a mined tile, the total number of flags, the total number of mines, and the board size.
#' @examples
#' x <- msBoard()
#' @seealso \code{\link{msweepeR}}
#' @export
msBoard <- function(w = 10, h = 10, m = as.integer(5)) {
#Obtener ancho de la pantalla
console_width <- options("width")
#Verificar parámetros
if (w < 3) stop("Board must be at least 3 tiles wide")
if (h < 3) stop("Board must be at least 3 tiles tall")
if ( (w * 3 + nchar(h) + 1 ) >= console_width) {
stop("Board is wider than the console output")
}
if (!is.integer(m) | m < 1 ) stop("Mines number must be a positive integer!")
if (m > (w*h*0.25)) warning("You're confident on your minesweeping levels")
if (m > (w*h*0.5)) stop("More than a half of the board tiles are mines!")
#Definir tamaño del tablero
board_size <- w * h
#Generar el tablero como una matriz
board <- matrix(nrow = h, ncol = w, data = 0)
#Definir aleatoreamente la posición de las minas
mine_location <- sample(1:board_size, m, replace = F)
#Colocar minas (-1)
board[mine_location] <- 1
#Calcular números en el tablero
numbers_board <- matrix(nrow = h, ncol = w, data = 0)
#Por cada columna
for (col in 1:ncol(board)) {
#Por cada fila
for (row in 1:nrow(board)) {
#Inicializar número de minas alrededor de la baldosa
n_mines <- 0
#Determinar si hay una mina
if (board[row, col] == 1) {
#Colocar -1 y pasar a siguiente iteración
numbers_board[row, col] <- -1
next()
}
#Definir coordenadas de las 8 baldosas al rededor
tile_no <- c(row - 1, col - 1)
tile_n <- c(row - 1, col)
tile_ne <- c(row - 1, col + 1)
tile_o <- c(row, col - 1)
tile_e <- c(row, col + 1)
tile_so <- c(row + 1, col - 1)
tile_s <- c(row + 1, col)
tile_se <- c(row + 1, col + 1)
#Ponerlas en una lista
tiles_coordinates <- list(tile_no, tile_n, tile_ne,
tile_o, tile_e,
tile_so, tile_s, tile_se)
#Iterar por cada una de las 8 baldosas al rededor
for (tile in tiles_coordinates) {
#Baldosa inválida
if (tile[1] < 1 | tile[1] > h) {
next()
}
#Baldosa inválida
if (tile[2] < 1 | tile[2] > w) {
next()
}
#Si hay mina, contarla
if (board[tile[1], tile[2]] == 1) {
n_mines <- n_mines + 1
}
}
numbers_board[row, col] <- n_mines
}
}
player_board <- matrix(nrow = h, ncol = w, data = 0)
return_obj <- list(board = board, size = c(w, h), mines = m,
turn = 0, player_mines = 0, player_board = player_board,
alive = 1, numbers_board = numbers_board)
return_obj <- structure(return_obj, class = "msBoard")
return(return_obj)
}
#' Check if an R object is a msweepeR board
#'
#' Tests whether an object is a msweepeR board (an R object of class \code{msBoard}).
#' @param x an R object.
#' @examples
#' x <- msBoard()
#' is.msBoard(x)
#' @seealso \code{\link{msweepeR}}, \code{\link{msBoard}}
#' @export
is.msBoard <- function(x) {
inherits(x, "msBoard")
}
#' Changes the state of a tile in a msweepeR board
#'
#' This method updates a msweepeR board by opening a tile or by placing a flag on it. If the opened
#' tile contains a mine, the game it's over.
#'
#' This method is called with the S3 method \code{\link{play.msweepeR}}, and it's recommended that
#' it's only called through such method.
#'
#' @param x A msweepeR board (an R object of class \code{msBoard}).
#' @param action A character vector of length 1. Valid options are: \code{"open"} and \code{"flag"}.
#' @param row Row number of the desired tile to interact with. Must be a positive integer.
#' Each tile in the game board has a [row, col] coordinate, ike any other matrix like object in R.
#' @param col Column number of the desired tile to interact with. Must be a positive integer.
#' Each tile in the game board has a [row, col] coordinate, like any other matrix like object in R.
#' @param warnings Logical vector of length 1. Indicates whether warnings are enabled.
#'
#' @return This method returns the updated msweepeR board (an R object of class \code{msBoard}).
#' @examples
#' x <- msBoard()
#' x <- change.msBoard(x, "open", 1, 1, FALSE)
#' @seealso \code{\link{msweepeR}}, \code{\link{msBoard}}
#' @export
change.msBoard <- function(x, action, row, col, warnings = TRUE) {
#Verificar objeto
if (!is.msBoard(x)) stop("This method is only available for msBoard objects")
#Obtener altura y longitud del tablero
w <- x$size[1]
h <- x$size[2]
#Obtener tablero de minas
board <- x$board
#Obtener tablero de jugador
player_board <- x$player_board
#Verificar parámetros
if (row > h | col > w) stop("Invalid tile coordinates")
if (row < 1 | col < 1) stop("Invalid tile coordinates")
#Hay dos acciones, revelar y bandera
#El usuario quiere revelar la casilla
if (action == "open") {
#Si hay mina, game over
if (board[row, col] == 1) {
if (warnings) warning("Ooops! You opened a mined tile x.x")
x$alive <- 0
} else {
player_board <- revealTile(board, player_board, row, col)
}
#El usuario quiere colocar una bandera
} else if (action == "flag") {
#Si ya está abierta, no hacer nada
if (player_board[row, col] != 1) {
player_board[row, col] <- 2
x$player_mines <- x$player_mines + 1
}
#Aacción desconocida
} else {
stop("Unknown action parameter. You can only update a board by revealing a
tile (action = 'reveal' or by putting a flag on a tile (action = 'flag')")
}
x$turn <- x$turn + 1
x$player_board <- player_board
return(x)
}
#' Draw a msweepeR board
#'
#' This method draws a msweepeR board into the output console. When drawing
#' the board game into the console, all tiles will have a white background.
#' \strong{Unopened tiles will have a black dot, while opened ones will be represented by one
#' blank space if they're empty or they will contain a number indicating the total number of mines in the 8 neighbouring tiles.}
#'
#' This method is called with the S3 method \code{\link{play.msweepeR}}, and it's recommended that
#' it's only called through such method.
#'
#' @param x A msweepeR board (an R object of class \code{msBoard}).
#' @examples
#' \dontrun{
#' x <- msBoard(); draw.msBoard(x)
#' }
#' @seealso \code{\link{msweepeR}}, \code{\link{msBoard}}
#' @export
draw.msBoard <- function(x) {
#Verificar objeto
if (!is.msBoard(x)) stop("This method is only available for msBoard objects")
#Obtener tablero del jugador y de numeros
player_board <- x$player_board
numbers_board <- x$numbers_board
#Obtener altura y longitud del tablero
w <- x$size[1]
h <- x$size[2]
#Imprimir número de fila
cat("\u001b[47m\u001b[30m")
cat(rep(" ", nchar(h) + 1 ), sep = "" )
cat(1:w, sep = " " )
cat("\n")
#Por cada fila
for (row in 1:nrow(player_board)) {
#Por cada columna
for (col in 1:(ncol(player_board) + 1) ) {
if (col == (ncol(player_board) + 1) ) {
cat("\n")
next()
}
cat("\u001b[47m\u001b[30m")
if (col == 1) {
cat(row, rep(" ", nchar(h) - nchar(row) ), sep = "" )
}
tile <- player_board[row, col]
under_tile <- numbers_board[row, col]
if (tile == 0) {
cat(" ",".", rep(" ", nchar(col) - 1), sep = "")
} else if (tile == 1) {
if (under_tile == 0) {
cat("\u001b[1m", " "," ", rep(" ", nchar(col) - 1), "\u001b[0m", sep = "")
} else {
cat("\u001b[1m", " ", msweepeR_colors[under_tile], rep(" ", nchar(col) - 1), "\u001b[0m", sep = "")
}
} else if (tile == 2) {
cat("\u001b[1m", " ", "F", rep(" ", nchar(col) - 1), "\u001b[0m", sep = "")
}
}
cat("\u001b[0m")
}
cat("\u001b[0m")
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.