#' Generate An R6-Class 'Action Squirrel' Game
#'
#' Prints to the console a grid of emoji representing an overworld,
#' including a player character that can be controlled by the user.
#' Also provides a live tally of moves taken.
#'
#' @return Console output with \code{cat()}.
#' @export
#'
#' @examples
#' \dontrun{
#' x <- ActionSquirrel$new() # generate overworld
#' x$move("up") # move character up
#' x$move("right") # move character right
#' }
ActionSquirrel <- R6::R6Class(
"ActionSquirrel",
public = list(
# FIELDS ----
#' @field active Logcial. Is the game in play?
active = TRUE,
#' @field overworld Character vector. The overworld in one dimension.
overworld = rep("\U1F333", 25),
#' @field s_loc Numeric. The location of the squirrel.
s_loc = 14,
#' @field n_loc Numeric. The location of the nut.
n_loc = 8,
#' @field o_loc Numeric. The location of the owl.
o_loc = 17,
#' @field moves Numeric. The number of moves made by the player.
moves = 0,
#' @field nuts Numeric. The number of nuts collected by the player.
nuts = 0,
# METHODS ----
#' @description Create a new overworld.
#' @return An R6-class object.
initialize = function() {
self$overworld[self$n_loc] <- "\U1F330"
self$overworld[self$s_loc] <- "\U1F43F"
self$overworld[self$o_loc] <- "\U1F989"
overworld_mat <- t(matrix(self$overworld, nrow = 5))
cat("\014")
for (i in seq(nrow(overworld_mat))) {
cat(overworld_mat[i, ], "\n")
}
cat("Moves:", self$moves, "\nNuts:", self$nuts)
},
#' @description Pause menu with instructions.
#' @return An R6-class object.
pause = function() {
cat(
"P A U S E\n",
"* Aim: get eight nuts before winter (30 moves)\n",
"* Move: e.g. x$move('up')\n",
"* Chain: e.g. x$move('u')$move('r')\n",
"* New game: x <- ActionSquirrel$new()\n",
"* Info: x$pause()\n",
"* Source: github.com/matt-dray/ActionSquirrel"
)
invisible(self)
},
#' @description Move the hero around the overworld.
#' @param where Character. Which direction to move. One of \code{"up"},
#' \code{"down"}, \code{"left"} and \code{"right"}.
#' @return An R6-class object.
move = function(where = c("up", "down", "left", "right")) {
where <- match.arg(where)
# If game is in play
if (self$active) {
# Stop at grid edge
if (
(where == "up" & self$s_loc %in% 1:5) |
(where == "down" & self$s_loc %in% 21:25) |
(where == "left" & self$s_loc %in% seq(1, 25, 5)) |
(where == "right" & self$s_loc %in% seq(5, 25, 5))
) {
sonify::sonify(1, 1, duration = 0.001)
sonify::sonify(1, 1, duration = 0.001)
return(cat("You reached the edge.\nTry another direction."))
}
# Increment grid location
if (where == "up") { move_n <- -5}
if (where == "down") { move_n <- +5}
if (where == "left") { move_n <- -1}
if (where == "right") { move_n <- +1}
self$s_loc <- self$s_loc + move_n
# Move sound
if (self$s_loc != self$n_loc) {
sonify::sonify(1, 1, duration = 0.01)
}
# Nut capture routine
if (self$s_loc == self$n_loc) {
sonify::sonify(c(1, 0), c(1, 0), duration = 0.1)
self$nuts <- self$nuts + 1 # increment nut tally
self$n_loc <- sample(seq(25)[-self$s_loc], 1) # new nut location
}
# Owl move
# corners
if (self$o_loc == 1) { o_move <- sample(c(0, 1, 5), 1) }
if (self$o_loc == 5) { o_move <- sample(c(0, -1, 5), 1) }
if (self$o_loc == 21) { o_move <- sample(c(0, 1, -5), 1) }
if (self$o_loc == 25) { o_move <- sample(c(0, -1, -5), 1) }
# edges
if (self$o_loc %in% 2:4) { o_move <- sample(c(0, -1, 1, 5), 1) }
if (self$o_loc %in% c(6, 11, 16)) { o_move <- sample(c(0, 1, -5, 5), 1) }
if (self$o_loc %in% c(10, 15, 20)) { o_move <- sample(c(0, -1, -5, 5), 1) }
if (self$o_loc %in% 22:24) { o_move <- sample(c(0, -1, 1, -5), 1) }
# middle
if (self$o_loc %in% c(7:9, 12:14, 17:19)) {
o_move <- sample(c(0, 1, -1, 5, -5), 1)
}
# increment
self$o_loc <- self$o_loc + o_move
# Create 1D grid
if (self$moves == 29) { # end of game
self$overworld <- sample(c("\U1F384", "\U26C4", "\U1F328"), 25, TRUE)
self$overworld[1] <- "\U1F43F️" # squirrel
if (self$nuts < 8) {
nut_diff <- 8 - self$nuts
self$overworld[2] <- "\U1F480" # skull
self$overworld[3:(self$nuts + 2)] <- "\U1F330" # nut
self$overworld[(self$nuts + 3):((self$nuts + 2) + nut_diff)] <- "\U274C" # cross
} else {
self$overworld[2] <- "\U1F4A4" # zzz
self$overworld[3:(self$nuts + 2)] <- "\U1F330" # nut
}
} else {
self$overworld <- rep("\U1F333", 25)
self$overworld[self$n_loc] <- "\U1F330"
self$overworld[self$s_loc] <- "\U1F43F️"
self$overworld[self$o_loc] <- "\U1F989"
}
# Death emoji
if (self$s_loc == self$o_loc) {
self$overworld[self$o_loc] <- "\U1F480" # skull
}
# Create 2D grid
overworld_mat <- t(matrix(self$overworld, nrow = 5))
# Clear console, print grid
cat("\014")
for (row in seq(nrow(overworld_mat))) {
cat(overworld_mat[row, ], "\n")
}
# Increment move tally, print move and nut tallies
self$moves <- self$moves + 1
cat("Moves:", self$moves, "\nNuts:", self$nuts)
# Owl attack routine
if (self$s_loc == self$o_loc) {
sonify::sonify(c(0, 2, 1), c(1, 1, 1), duration = 1)
cat(
"\nY O U D I E D !",
"\nThe owl ate you."
)
self$active <- FALSE # change active state
}
# End game routine
if (self$moves == 30) {
if (self$nuts < 8) { # lose
sonify::sonify(c(0, 2, 1), c(1, 1, 1), duration = 1)
cat(
"\nY O U D I E D !",
"\nInsufficient winter nut cache!"
)
}
if (self$nuts >= 8) { # win
sonify::sonify(c(0, 1), rep(1, 2), duration = 0.2)
sonify::sonify(c(0, 1), rep(1, 2), duration = 0.2)
sonify::sonify(c(0, 1), rep(1, 2), duration = 0.2)
cat(
"\nY O U S U R V I V E D !",
"\nSufficient winter nut cache!"
)
}
self$active <- FALSE # change active state
}
}
# If game is over
if (!self$active) {
cat(
"\nG A M E O V E R",
"\n* New game: x <- ActionSquirrel$new()",
"\n* Source: github.com/matt-dray/ActionSquirrel"
)
}
invisible(self)
}
)
)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.