Little useless-useful R functions – Desk plant simulator

R-bloggers 2026-04-27

[This article was first published on R – TomazTsql, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
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 playget_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 infoget_stage <- function(points) {  stage_idx <- max(which(growth_stages$min_points <= points))  growth_stages[stage_idx, ]}# get appropriate ASCII art plantget_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 chatGPTget_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 healthget_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 functionsPlantNew <- 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 plantCheckPlant <- 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 plantPlant <- 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 checklocal({  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.

To leave a comment for the author, please follow the link and comment on their blog: R – TomazTsql.

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.
Continue reading: Little useless-useful R functions – Desk plant simulator