Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
This time, we will create a Desk plant simulator. And for that we need a set of different functions
Yes, we will grow a R plant in a simulation game with lots of twerks and hidden gems and ASCII art
And how this set of functions really work?
Storing the daily progress in an RDS. Before running set of functions, you will prepare a location to store the RDS file (environment variables and game play)
.plant_file <- path.expand("~/.r_desk_plant.rds")
ASCII art was done by GPT for all the stages and it is so nice
plant_art <- list( # Stage 0: Seed seed = c( " ", " ", " ", " ", " . ", " (.) ", " ----- ", " | | ", " |~~~~~| ", " |_____| " ), # Stage 1: Sprout sprout = c( " ", " ", " ", " , ", " (') ", " | ", " ----- ", " | | ", " |~~~~~| ", " |_____| " ), # Stage 2: Seedling seedling = c( " ", " ", " \\|/ ", " \\|||/ ", " ||| ", " ||| ", " ----- ", " | | ", " |~~~~~| ", " |_____| " ), # Stage 3: Young plant young = c( " ", " \\~~/ ", " \\\\|// ", " \\|/ ", " ||| ", " ||| ", " ----- ", " | | ", " |~~~~~| ", " |_____| " ),......
Then you will have helper and main functions available. Complete code is available on my Github repository.
To run the game you will need to plant a new plant, water it, check the plant status and many others.
PlantNew() # Start a new plant (choose a name!)WaterPlant() # Water your plant (once per day)CheckPlant() # Full status reportPlant() # Quick view (just the art)
Here is an excerpt from the code:
hline <- function(char = "β", n = 40) strrep(char, n)
# get current status of a plant / game play
get_plant <- function(file = .plant_file) {
if (file.exists(file)) { readRDS(file) }
}
# Save plant in RDS and all game play!
save_plant <- function(plant, file = .plant_file) {
saveRDS(plant, file)
}
# get growth info
get_stage <- function(points) {
stage_idx <- max(which(growth_stages$min_points <= points))
growth_stages[stage_idx, ]
}
# get appropriate ASCII art plant
get_plant_art <- function(plant) {
if (plant$health <= 0) {
return(plant_art$dead)
}
if (plant$health < 30) {
return(plant_art$wilted)
}
stage <- get_stage(plant$points)
plant_art[[stage$art_name]]
}
days_since <- function(date) {
as.integer(Sys.Date() - as.Date(date))
}
# Messages for encouragement - Done with help of chatGPT
get_encouragement <- function() {
messages <- c(
"Your plant appreciates you!",
"Keep up the great work!",
"You're a natural plant parent!",
"Your R sessions make the plant happy!",
"Photosynthesis in progress... ",
"Growing strong, just like your R skills!",
"The plant sends positive vibes!",
"Another day, another leaf!",
"Your dedication is blooming!",
"Keep coding, keep growing!"
)
sample(messages, 1)
}
# General health
get_health_message <- function(health) {
if (health >= 90) {
return("Thriving! Your plant is radiantly healthy!")
} else if (health >= 70) {
return("Healthy! Looking good!")
} else if (health >= 50) {
return("Okay. Could use some attention.")
} else if (health >= 30) {
return("Struggling. Please water me!")
} else if (health > 0) {
return("Critical! Water immediately or I'll die!")
} else {
return("Your plant has died. Start a new one with PlantNew()")
}
}
# ---- main functions
PlantNew <- function(name = NULL, file = .plant_file) {
existing <- get_plant(file)
if (!is.null(existing) && existing$health > 0) {
cat(" You already have a plant named '", existing$name, "'!\n", sep = "")
cat(" Health: ", existing$health, "% | Stage: ",
get_stage(existing$points)$name, "\n\n", sep = "")
cat(" Are you sure you want to replace it? (yes/no): ")
response <- tolower(readline())
if (response != "yes") {
cat(" Keeping your existing plant. \n\n")
}
}
# Get plant name
if (is.null(name)) {
suggestions <- c("Fernie Bennes", "Morgan Treeman", "Leaf Seinfeld",
"Plantonio Banderas", "Elvis Parsley", "Kramerofern",
"Snake Costanza", "Aloe NewmanVera", "Jungle Tribbiani")
cat("\n")
cat(" NEW PLANT!\n")
cat(" Some name suggestions:\n")
for (i in seq_along(suggestions)) {
cat(sprintf(" %d. %s\n", i, suggestions[i]))
}
cat("\n Enter a name (or number, or press Enter for random): ")
input <- readline()
if (input == "") {
name <- sample(suggestions, 1)
} else if (grepl("^[0-9]+$", input)) {
idx <- as.integer(input)
if (idx >= 1 && idx <= length(suggestions)) {
name <- suggestions[idx]
} else {
name <- input
}
} else {
name <- input
}
}
# Create new plant
plant <- list(
name = name,
species = "R-Plant (Programmus enthusiasticus)",
planted_date = Sys.Date(),
last_watered = Sys.Date(),
last_visited = Sys.time(),
points = 0,
health = 100,
times_watered = 0,
sessions = 0,
achievements = character(0)
)
save_plant(plant, file)
cat("\n")
cat(" β", hline("β", 44), "β\n", sep = "")
cat(" β NEW PLANT CREATED! β\n")
cat(" β", hline("β", 44), "β\n", sep = "")
cat("\n")
art <- plant_art$seed
for (line in art) {
cat(" ", line, "\n", sep = "")
}
cat("\n")
cat("Name: ", name, "\n", sep = "")
cat("Species: ", plant$species, "\n", sep = "")
cat("Planted: ", format(Sys.Date(), "%B %d, %Y"), "\n", sep = "")
cat("\n")
cat("Tips:\n")
cat(" --> Use WaterPlant() to water your plant\n")
cat(" --> Use CheckPlant() to see its status\n")
cat(" --> Visit often - your R sessions help it grow!\n")
cat("\n")
}
# -- Water planting
WaterPlant <- function(file = .plant_file) {
plant <- get_plant(file)
if (is.null(plant)) {
cat("\n No plant found! Start one with PlantNew()\n\n")
}
if (plant$health <= 0) {
cat("\n Your plant has died. Start a new one with PlantNew()\n\n")
}
# Check if already watered today
last_water_date <- as.Date(plant$last_watered)
today <- Sys.Date()
if (last_water_date == today) {
cat("\n")
cat(" Already watered today!\n")
cat(" Your plant doesn't want to drown. \n")
cat(" Come back tomorrow!\n\n")
return(invisible(plant))
}
# Calculate bonus for consecutive days
days_since_water <- days_since(plant$last_watered)
water_points <- 15
health_gain <- 20
if (days_since_water == 1) {
water_points <- water_points + 5 # Consecutive day bonus
plant$achievements <- union(plant$achievements, "daily_waterer")
}
plant$last_watered <- today
plant$points <- plant$points + water_points
plant$health <- min(100, plant$health + health_gain)
plant$times_watered <- plant$times_watered + 1
plant$last_visited <- Sys.time()
# Check for achievements
if (plant$times_watered == 10 && !"10_waters" %in% plant$achievements) {
plant$achievements <- c(plant$achievements, "10_waters")
}
if (plant$times_watered == 50 && !"50_waters" %in% plant$achievements) {
plant$achievements <- c(plant$achievements, "50_waters")
}
save_plant(plant, file)
# Get stage info
old_stage <- get_stage(plant$points - water_points)
new_stage <- get_stage(plant$points)
leveled_up <- new_stage$stage > old_stage$stage
# Display
cat("\n")
cat(" β", hline("β", 44), "β\n", sep = "")
cat(" β WATERING TIME! β\n")
cat(" β", hline("β", 44), "β\n", sep = "")
cat("\n")
cat(" Watering '", plant$name, "'...\n\n", sep = "")
art <- get_plant_art(plant)
for (line in art) {
cat(" ", line, "\n", sep = "")
}
cat(sprintf(" +%d growth points! (Total: %d)\n", water_points, plant$points))
cat(sprintf(" Health: %d%% %s\n", plant$health, strrep("β", plant$health %/% 10)))
if (leveled_up) {
cat("\n")
cat(" β", hline("β", 44), "β\n", sep = "")
cat(" LEVEL UP! Your plant is now: ", new_stage$emoji, " ", new_stage$name, "\n", sep = "")
cat(" β", hline("β", 44), "β\n", sep = "")
}
cat("\n ", get_encouragement(), "\n\n", sep = "")
}
# -- Check on your desk plant
CheckPlant <- function(file = .plant_file) {
plant <- get_plant(file)
if (is.null(plant)) {
cat("\n No plant found! Start one with PlantNew()\n\n")
}
days_without_water <- days_since(plant$last_watered)
if (days_without_water > 1 && plant$health > 0) {
# Lose health for each day without water (after first day)
health_loss <- (days_without_water - 1) * 10
plant$health <- max(0, plant$health - health_loss)
}
session_start <- Sys.getenv("R_SESSION_TMPDIR") # Unique per session
visit_points <- 2
plant$points <- plant$points + visit_points
plant$sessions <- plant$sessions + 1
plant$last_visited <- Sys.time()
if (plant$sessions == 100 && !"100_sessions" %in% plant$achievements) {
plant$achievements <- c(plant$achievements, "100_sessions")
}
save_plant(plant, file)
# Get stage info
stage <- get_stage(plant$points)
days_alive <- days_since(plant$planted_date)
# Display
cat("\n")
cat(" β", hline("β", 44), "β\n", sep = "")
cat(" β PLANT STATUS REPORT β\n")
cat(" β", hline("β", 44), "β\n", sep = "")
cat("\n")
# Show art
art <- get_plant_art(plant)
for (line in art) {
cat(" ", line, "\n", sep = "")
}
cat("\n")
cat(" ", hline("β", 44), "\n", sep = "")
cat(sprintf(" Name: %s\n", plant$name))
cat(sprintf(" Age: %d day%s old\n", days_alive, if(days_alive != 1) "s" else ""))
cat(sprintf(" Stage: %s %s\n", stage$emoji, stage$name))
cat(sprintf(" Points: %d / %d (next stage)\n",
plant$points,
ifelse(stage$stage < 7, growth_stages$min_points[stage$stage + 2], "MAX")))
cat(" ", hline("β", 44), "\n", sep = "")
# Health bar
health_bar <- paste0(
strrep("β", plant$health %/% 10),
strrep("β", 10 - plant$health %/% 10)
)
cat(sprintf(" Health: [%s] %d%%\n", health_bar, plant$health))
cat(sprintf(" Status: %s\n", get_health_message(plant$health)))
cat(" ", hline("β", 44), "\n", sep = "")
# Water status
days_since_water <- days_since(plant$last_watered)
if (days_since_water == 0) {
water_status <- " Watered today!"
} else if (days_since_water == 1) {
water_status <- " Watered yesterday"
} else {
water_status <- sprintf(" %d days without water!", days_since_water)
}
cat(sprintf(" Last water: %s\n", water_status))
cat(" ", hline("β", 44), "\n", sep = "")
# Stats
cat(sprintf(" Waterings: %d total\n", plant$times_watered))
cat(sprintf(" Visits: %d R sessions\n", plant$sessions))
# Achievements
if (length(plant$achievements) > 0) {
cat(" ", hline("β", 44), "\n", sep = "")
cat(" Achievements:\n")
achievement_names <- list(
"daily_waterer" = "Daily Waterer - Watered on consecutive days",
"10_waters" = "Hydration Helper - Watered 10 times",
"50_waters" = "Water Master - Watered 50 times",
"100_sessions" = "Dedicated Parent - 100 R sessions"
)
for (ach in plant$achievements) {
if (ach %in% names(achievement_names)) {
cat(sprintf(" %s\n", achievement_names[[ach]]))
}
}
}
if (days_since_water >= 1 && plant$health > 0) {
cat(" Don't forget to WaterPlant()!\n\n")
}
}
# Quick status - just show the plant
Plant <- function(file = .plant_file) {
plant <- get_plant(file)
if (is.null(plant)) {
cat("\n No plant! Use PlantNew() to start.\n\n")
}
# Update health decay silently
days_without_water <- days_since(plant$last_watered)
if (days_without_water > 1 && plant$health > 0) {
health_loss <- (days_without_water - 1) * 10
plant$health <- max(0, plant$health - health_loss)
save_plant(plant, file)
}
stage <- get_stage(plant$points)
art <- get_plant_art(plant)
cat("\n")
for (line in art) {
cat(" ", line, "\n", sep = "")
}
cat("\n")
cat(sprintf(" %s %s | Day %d | %d%% health\n",
stage$emoji, plant$name,
days_since(plant$planted_date),
plant$health))
cat("\n")
}
PlantDelete <- function(file = .plant_file, confirm = TRUE) {
plant <- get_plant(file)
if (is.null(plant)) {
cat("\n No plant to delete.\n\n")
return(invisible(FALSE))
}
if (confirm) {
cat("\n Are you sure you want to delete '", plant$name, "'?\n", sep = "")
cat(" This cannot be undone! (yes/no): ")
response <- tolower(readline())
if (response != "yes") {
cat(" Keeping your plant safe. \n\n")
}
}
file.remove(file)
cat("\n Goodbye, ", plant$name, "...\n", sep = "")
cat(" Use PlantNew() to start fresh.\n\n")
}
#optional
.onAttach <- function() {
plant <- get_plant()
if (!is.null(plant) && plant$health > 0) {
stage <- get_stage(plant$points)
message(sprintf(" Your plant '%s' (%s) is waiting! Use CheckPlant() to visit.",
plant$name, stage$name))
}
}
# Run welcome check
local({
plant <- get_plant()
if (!is.null(plant) && plant$health > 0) {
days_without_water <- days_since(plant$last_watered)
stage <- get_stage(plant$points)
cat(sprintf("\n '%s' says hello! (%s, Day %d)\n",
plant$name, stage$name, days_since(plant$planted_date)))
if (days_without_water >= 2) {
cat(sprintf("It's been %d days without water!\n", days_without_water))
}
cat("\n")
}
})
PRO-tips:
- Water daily for bonus points
- Just running CheckPlant() gives small growth points
- Donβt forget to water or your plant will wilt!
- Health below 30% = wilted, Health 0% = dead
As always, the complete code is available on GitHub in Β Useless_R_function repository. The Plant simulator isΒ hereΒ (filename:Β plant_tame.R).
Check the repository for future updates!
Stay healthy and happy R-coding!
Disclaimer: all ASCII art was done by GPT, as well as plant names and ASCII game progress.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
