astRaRium2: An R Game About Linking Stars
José Hidasi-Neto
Post-Doc em Ecologia e Evolu??o | Desenvolvedor de Jogos | Data Analyst | Unity, Unreal | Game Designer | Power BI | R, Python, C#, C++ | Brasileiro-Húngaro |
Hi there,
Today I have a game I created in R for you. I named it astRaRium, and it's Puzzle game about identifying and reproducing image patterns. I thought about making this code after playing a famous RPG game named "Dragon Age: Inquisition". There is a mini-game (named Astrarium) where you have to find a route among stars that generated the same pattern you saw in another image. In other words, you have to trace "constellations", but using some machines named "Astrariums" (or "Astraria"; see?https://en.wikipedia.org/wiki/Astrarium). See the image below to have an idea on how that game worked. Note that stars are being connected in sequence to generate the pattern seen in the lower right corner of the screen. It's not as easy as it seems. When you connect two stars, you have to continue from the last star you selected.
I wanted to simulate any number of constellations I desired. So, here we have "AstRaRium". I'll explain the rules. It's simple. Observe the following puzzle example. It's an astrarium generated with 12 stars (on the right) where you have to find the sequence of stars corresponding to 7 distinct links (on the left). Try to solve it and go on. Remember that you cannot repeat connections, and must always continue from the last star you stopped at.
Did you find the answer? I'll tell you one possible answer (sequence of connected stars): 10, 11, 12, 2, 7, 10, 6, 11. Note that star 7 is hidden within links 2-10 and 6-11. It's always good to remember that the number of connected stars is always = number of links?+ 1. Cool, isn't it? So here I have a Tutorial explaining how to play it in R.
Extra: A little Math behind the game!
The constellations shown here are examples of Eulerian paths. Eulerian paths are paths in graphs that do not repeat the same edges. There are two types of Eulerian paths: (type 1) those having two vertices (stars) connected by an odd number of edges (connections or links), and (type 2) those that only have vertices (stars) connected by an even number of links. This second type of path is called Eulerian circuit (subtype of Eulerian path). Type 1 paths always start on one of the two vertices (stars) with an odd number of vertices, whereas type 2 paths start at any vertex (star). In this update we do not use Eulerian circuits.
TUTORIAL
### 1. Open R ###
### 2. Install these two packages (if you don't have them):
install.packages("data.table")
install.packages("stringr")
### 3. Now load them:
领英推荐
library(data.table)
library(stringr)
### 4. Then, copy and paste all this code below into R:
astrarium2<-function(){
stars<-readline(" How many stars? Choose from 5 to 28. ")
stars<-as.numeric(stars)
links<-readline(" How many links between stars? Choose from 1 to 10. ")
links<-as.numeric(links)
x<-NULL
y<-NULL
poolx<-c(0:100)
pooly<-c(0:100)
for(i in 1:stars){
x<-c(x,sample(poolx,1))
poolx<-poolx[-which(poolx%in%c((x[i]-2):(x[i]+2)))]
y<-c(y,sample(pooly,1))
pooly<-pooly[-which(pooly%in%c((y[i]-2):(y[i]+2)))]}
count.dups <- function(DF){
DT <- data.table(DF)
DT[,.N, by = names(DT)]}
seq_gen_rand_total=function(item_count){
last_item=-1
last_last_item=-1
rand_seq=NULL
item_total=sum(item_count)
item_prob=cumsum(item_count)/item_total
while (sum(item_count) > 0){
r_n=runif(1, 0, 1)
new_item=which(r_n < item_prob)[1]
if (new_item != last_item){
if (item_count[new_item] > 0){
rand_seq=c(rand_seq, new_item)
last_last_item=last_item
last_item=new_item
item_count[new_item]=item_count[new_item]-1}}
else
if ((length(which(item_count != 0)) == 1) & (which(item_count != 0)[1] == last_item))
return(0)}
noback<-0
for(j in 3:(links+1)){
noback<-c(noback,rand_seq[j]==rand_seq[j-2])}
reps<-NULL
for(p in 1:(links+1)){
reps<-rbind(reps,c(rand_seq[p],rand_seq[p+1]))
reps<-rbind(reps,c(rand_seq[p+1],rand_seq[p]))}
ifelse(sum(noback)==0 & max(count.dups(reps)[[3]])==1, return(rand_seq[1:(links+1)]),return(0))
return(rand_seq)}
randlink<-0
while(sum(randlink)==0 || table(randlink)[1]<=1 || randlink[1]!=randlink[length(randlink)]){randlink<-seq_gen_rand_total(1:stars)}
seqs<-randlink[1:(links+1)]
reps<-NULL
for(p in 1:(links)){
reps<-rbind(reps,c(seqs[p],seqs[p+1]))}
predanswer<-reps[order(reps[,2],reps[,1]),]
dev.new(width=40, height=20)
par(mfrow = c(1,2))
plot(0:100,0:100,pch=NA,xlab=NA,ylab=NA,axes=F)
for(l in 1:(links)){
segments(x[seqs[l]], y[seqs[l]], x[seqs[l+1]], y[seqs[l+1]])}
plot(0:100,0:100,pch=NA,xlab=NA,ylab=NA,axes=F)
points(x,y,cex=1,pch=8)
text(x,y+3,cex=0.8)
pick.one<-readline(" To give a solution: press 1 and ENTER. To see a solution: another key and ENTER. Answer: ")
ifelse(pick.one=="",pick.one<-2,NA)
ifelse(pick.one==1, NA, return(paste("Star",as.numeric(seqs))))
answer<-readline("Select the connected stars. Example: 3, 1, 4. Press ENTER to begin: ")
seqans<-numeric(links+1)
seqans[1]=identify(x,y,n=1, plot=FALSE)
for(i in 2:(links+1)){
seqans[i]=identify(x,y,n=1,plot=FALSE)
segments(x[seqans[i-1]],y[seqans[i-1]],x[seqans[i]],y[seqans[i]])}
answer<-seqans
ifelse(length(answer)==length(seqs), NA, return("Wrong number of connected stars (n of links + 1)"))
reps2<-NULL
for(p in 1:(links)){
reps2<-rbind(reps2,c(answer[p],answer[p+1]))
reps3<-reps2[,2:1]}
obsanswer<-reps2[order(reps2[,2],reps2[,1]),]
obsanswer2<-reps3[order(reps3[,2],reps3[,1]),]
ifelse(length(obsanswer2==predanswer)==sum(obsanswer2==predanswer) | length(obsanswer==predanswer)==sum(obsanswer==predanswer),return(print("CORRECT! YOU'RE GREAT!")), print("Wrong! Try again! See an answer:"))
return(seqs)}
### Stop copying now and paste it into R ###
### 5. Time to play! Call the function by typing "astrarium2()" and pressing ENTER. It will ask you the desired number of stars and the number of links between pairs of stars. A good number is 12 and 9, respectively. For example:
astrarium2()
### 6. It will then ask you if you want to either give a solution (press 1 and ENTER) or to give up and see a solution (another key and ENTER). Then (if you type 1 and ENTER), you'll need to select the sequence of stars (pressing mouse button over the stars). In the example, you could have pressed stars "12,10,7,8,10,5,8,2,7,1". But it would be wrong, so it would say:
"Wrong! Try again! See an answer:"
"12,10,7,9,12,5,8,12,7,5"
# If correct, it will say:
"CORRECT! YOU'RE GREAT!"
Here is a video of how to play the game:
That's it for now. Feel free to comment.
Till' next time!