2048 in R
- A simple/naive implementation of 2048 in plain R - with
{ggplot2}
output
for a little bit of zing.
- Interactive keypress response seems basically impossible from R, so
this uses
readline()
and you have to press return to register each
action.
- Code in a gist
- Motivation:
- Looking at some game stuff in R and this was the simplest thing I
could think to write
- There’s an existing package on CRAN: twenty48
- But I wanted to re-invent the wheel so I could think about the process
of game creation.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ##### ### # #####
# # # # # # # # #
# # # # # # # #
# ##### # # # # #####
# # # # ####### # #
# # # # # # #
# ####### ### # #####
#
#
#
# Board Size: Default = 4
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library(ggplot2)
N <- 4L
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Collapse a vector in the style of 2048
#
# Collapse vector by removing zeros, then summing pairs of adjacent values
#
# Result is padded with zeros to length of input
#
# @param x vector of integers
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
collapse_vec <- function(x) {
new <- x[x > 0]
i <- 1L
while (i < length(new)) {
if (new[i] == new[i + 1L]) {
new[i] <- new[i] * 2L
new <- new[-(i + 1L)]
}
i <- i + 1L
}
c(new, integer(N - length(new)))
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Initialise game board
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
m <- matrix(0L, N, N)
init <- sample(N*N, 2)
m[init] <- 2L
m_prior <- m
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Plot game board
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
plot_m <- function(m) {
grid <- expand.grid(1:N, 1:N)
idx <- arrayInd(which(m > 0), .dim = c(N, N))
df <- cbind(as.data.frame(idx), V3 = factor(m[m > 0], levels = 2^(1:11)))
ggplot(df, aes(V2, N + 1L - V1)) +
geom_tile(data = grid, aes(Var1, Var2), fill = 'grey90', width = 0.9, height = 0.9) +
geom_tile(aes(fill = V3), width = 0.9, height = 0.9) +
geom_text(aes(label = V3), colour = 'white', size = 10) +
theme_void() +
xlim(0, N+1L) + ylim(0, N+1L) +
coord_equal() +
theme(legend.position = 'none') +
scale_fill_viridis_d(option = 'D', drop = FALSE, end = 0.9)
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Game loop
# Use WASD to collapse the board in up/left/down/right directions
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
print(plot_m(m))
while (max(m) < 2048 && any(m == 0)) {
if (!identical(m, m_prior)) {
# if the board has changed, then add a new '2' tile
m[sample(which(m == 0), 1)] <- 2L
print(m)
print(plot_m(m))
}
m_prior <- m
# cmd <- readline(prompt = "move?: ")
m <- switch(
readline(prompt = "move?: "),
'q' = break,
'w' = apply(m, 2, collapse_vec), # up
'a' = t(apply(m, 1, collapse_vec)), # left
's' = apply(m[nrow(m):1,], 2, collapse_vec)[nrow(m):1,] , # down
'd' = t(apply(m[,nrow(m):1], 1, collapse_vec))[,nrow(m):1], # right
m
)
}
if (max(m) >= 2048) {
message("You won!")
}