Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
I love when people take a sophisticated tool and use it to play video games. Take R for example. I first saw someone create a game for R at talk.stats.com. My friend Dason inspired me to more efficiently waste time in R with his version of minesweeper. The other day I had an immense amount of work to do and decided it was the perfect time to make a hangman game.
Now some of the skills to create hangman were outside my typical uses and skills for R. It caused me to stretch and grow a bit. The purpose of this post is two fold:
- To share the hangman game with people who have nothing better to do than waste time on a childhood game
- To share the learning experiences I had in creating the game
First the hangman game
I have the code for the function posted here but I have saved the code and data set (word list) for the function at github. You can download the package that contains the hangman game and data set by either downloading the zip ball or tar ball, decompress and run R CMD INSTALL on it, or use the devtools package to install the development version:
# install.packages("devtools") library(devtools) install_github("hangman", "trinker")
To play type hangman() into the console and hit enter.
Here’s a screenshot of the game
Now for the learning
Here’s the code for the hangman function:
hangman opar on.exit(par(mar = opar)) par(mar = rep(0, 4)) x1 x len x2 chance if(!exists("wins", mode="numeric", envir = .GlobalEnv) | reset.score){ assign("wins", 0, envir = .GlobalEnv) } if(!exists("losses", mode="numeric", envir = .GlobalEnv) | reset.score){ assign("losses", 0, envir = .GlobalEnv) } win1 win wrong right print(x2, quote = FALSE) circle lwd = NULL){ units if (units == "cm") radius plot.size plot.units units.x units.y ratio size angles unit.circle shape ellipse lines(ellipse, lwd = lwd) } #taken from John Fox: http://tolstoy.newcastle.edu.au/R/help/06/04/25821.html hang.plot plot.new() parts if (identical(wrong, character(0))) { parts } text(.5, .9, "HANGMAN", col = "blue", cex=2) if (!6 %in% parts) { text(.5, .1, paste(x2, collapse = " "), cex=1.5) } text(.05, .86, "wrong", cex=1.5, col = "red") text(.94, .86,"correct", cex=1.5, col = "red") text(.05, .83, paste(wrong, collapse = "\n"), offset=.3, cex=1.5, adj=c(0,1)) text(.94, .83, paste(right, collapse = "\n"), offset=.3, cex=1.5, adj=c(0,1)) segments(.365, .77, .365, .83, lwd=2) segments(.365, .83, .625, .83, lwd=2) segments(.625, .83, .625, .25, lwd=2) segments(.58, .25, .675, .25, lwd=2) if (1 %in% parts) { circle(.365, .73, .7, lwd=4) if (!6 %in% parts) { text(.365, .745, "o o", cex=1) } if (!5 %in% parts) { text(.365, .71, "__", cex = 1) } text(.36, .73, "<", cex=1) } if (2 %in% parts) { segments(.365, .685, .365, .4245, lwd=7) } if (3 %in% parts) { segments(.365, .57, .45, .63, lwd=7) } if (4 %in% parts) { segments(.365, .57, .29, .63, lwd=7) } if (5 %in% parts) { segments(.365, .426, .43, .3, lwd=7) text(.365, .71, "O", cex = 1.25, col = "red") } if (6 %in% parts) { segments(.365, .426, .31, .3, lwd = 7) text(.365, .745, "x x", cex=1) text(.5, .5, "You Lose", cex=8, col = "darkgreen") text(.5, .1, paste(x, collapse = " "), cex=1.5) } if (win1 == len) { text(.5, .5, "WINNER!", cex=8, col = "green") text(.505, .505, "WINNER!", cex=8, col = "darkgreen") } } #end of hang.plot guess cat("\n","Choose a letter:","\n") y if (y %in% c(right, wrong)) { stop(paste0("You've already guessed ", y)) } if (!y %in% letters) { stop(paste0(y, " is not a letter")) } if (y %in% x) { right < win1 < win < message(paste0("Correct!","\n")) } else { wrong < chance < message(paste0("The word does not contain ", y, "\n")) } x2[x %in% right] < print(x2, quote = FALSE) hang.plot() }#end of guess function hang.plot() while(all(win1 != len & chance < 6)){ try(guess()) } if (win == 1) { outcome <- "\nCongratulations! You Win!\n" assign("wins", wins + 1, envir = .GlobalEnv) } else { outcome assign("losses", losses + 1, envir = .GlobalEnv) } cat(outcome) cat(paste0("\nwins: ", wins, " | losses: ", losses, "\n")) text(.5, .2, paste0("wins: ", wins, " | losses: ", losses), cex = 3, col = "violetred") }
Things I tried and learned:
- Translating simple game rules into systematic logic
- try
- plotting dynamically (text vs. mtext)
- while loop
- assign
I used try one other time in a web scraping function. If you don’t know anything about this function it allows you to try to do something and if an error occurs move onto the next step. This allows the game user to input wrong information yet the function doesn’t stop but instead recovers and prints a message.
I first tried plotting the symbols and text with mtext. Thanks to some help at stack.overflow I found out the text function is a more controllable choice. I also grabbed a circle plotting function from John Fox to avoid calling a package that plots circles.
This was my first need for a while loop (generally I use the apply functions but in this case the game logic demanded I repeat something until one of two circumstances were met (win or loss of the game)
assign is a nice function and I generally don’t use it as I can get away with <<- (cringe if you want but if you think it through the <<- operator can be handy.
So I encourage you to write your own R game as you’ll likely learn a bit, while effectively wasting time and will provide enjoyment to others.
Warning: not tested on a Linux or Mac machine
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.