|
| 1 | +# for truly absurd fun, write 2048 for R |
| 2 | +# This will be a cheap, sloppy version at best. Use readline to get the next |
| 3 | +# direction of motion and re-draw the grid with the new numbers. Track empty cells |
| 4 | +# and fill one randomly on each cycle. Establish a "top-to-bottom" sort of algorithm |
| 5 | +# to determine which pair of 3-in-a-row get merged. And so on |
| 6 | +# figure out options later, if any |
| 7 | +# and how are points awarded? Wiki says value of new tile(s); also says |
| 8 | +# new tile might be a 4 as well as a 2. hmmm... that's an input option to do |
| 9 | +#Since it's 4x4, keep things simple by tracking cells in a 16-elt vector. |
| 10 | +## for first round, just do ascii |
| 11 | +# |
| 12 | +# TODO |
| 13 | +# |
| 14 | +# |
| 15 | +play2048<-function(brd=structure(list(score=0,brd=matrix(0,4,4)),class='brd2048') ) { |
| 16 | + |
| 17 | +# init |
| 18 | +#brd<-matrix(0,4,4) |
| 19 | +if (! 'brd2048'%in%class(brd) ) stop('Input must be of class "brd2048".') |
| 20 | + score <- brd$score |
| 21 | + brd <- brd$brd |
| 22 | +# now check for newness |
| 23 | +if ( !sum(brd) ) { |
| 24 | + newspot <- sample(1:16,2) |
| 25 | + brd[newspot] <- sample(c(2,4),2,rep=TRUE,prob=c(.9,.1)) |
| 26 | + score <- 0 |
| 27 | + } |
| 28 | +print(brd) |
| 29 | +#it's OK for board to be full, just not full AND no legal move! |
| 30 | +# so add a comparison with "oldbrd" . In fact, a good "tag" can replace the |
| 31 | +## identical() test, I think. |
| 32 | +# probably need an initial tag value here, as |
| 33 | +# tag<-c(FALSE,FALSE,FALSE) |
| 34 | +# then the conditional could be !(sum(tag)) |
| 35 | +youlose<-FALSE |
| 36 | +while (length(which(brd==0)) || !youlose ) { |
| 37 | + #bustamove |
| 38 | + oldbrd <- brd # for later comparison |
| 39 | + move<-readline('u,d,l,r,s(ave)? ') |
| 40 | + # first flipflop matrix, do move, flopflip back |
| 41 | + |
| 42 | + switch(move, |
| 43 | + 'u'=brd <- brd[4:1,] , # flip(brd,1), |
| 44 | + 'l' = brd <- t(brd)[4:1,], #flip(t(brd),1), |
| 45 | + 'r' = brd <- t(brd)[,4:1] , #flip(t(brd),2), |
| 46 | + 'd' = "", #do nothing |
| 47 | + 's' = {savebrd<-structure(list(score=score,brd=brd),class='brd2048'); assign('savebrd',savebrd,env=.GlobalEnv);print("Game saved to 'savebrd'");return(invisible() ) } #just to bail out |
| 48 | + ) |
| 49 | + |
| 50 | +getsq <- squoosh(brd) |
| 51 | +brd<-getsq$brd |
| 52 | +score <- score + getsq$score |
| 53 | + |
| 54 | + # re-orient board |
| 55 | + switch(move, |
| 56 | + 'u'=brd<- brd[4:1,] , #flip(brd,1), |
| 57 | + 'l' = brd <- t(brd)[,4:1], #flip(t(brd),2), |
| 58 | + 'r' = brd <- t(brd)[4:1,], |
| 59 | + 'd' = '' ) # flip(t(brd),1) ) |
| 60 | +## check that it was a legal, i.e. productive, move |
| 61 | +## or the board is full and jammed. So when the board is full, |
| 62 | +## AND the selected move caused no change, need to "call" all 3 other moves |
| 63 | +## to see if any produce a change, and if so, skip to "illegal move try again" |
| 64 | +## option. |
| 65 | + if ( identical(brd, oldbrd) ) { |
| 66 | + if(!length(which(brd==0))) { |
| 67 | + # here is where I'll need to cycle thru (u,d,l,r)!%in% move , so to speak |
| 68 | + # and if any of them get !identical, then want 'try again' |
| 69 | + trymov<- c('u','d','l','r') |
| 70 | + trymov<-trymov[! trymov%in% move] |
| 71 | + idtag<-vector(length=3) |
| 72 | + tmpbrd<-brd |
| 73 | + for( jj in 1:3) { |
| 74 | + switch(trymov[jj], |
| 75 | + 'u'=tmpbrd<- tmpbrd[4:1,] , #flip(tmpbrd,1), |
| 76 | + 'l' = tmpbrd <- t(tmpbrd)[,4:1], #flip(t(tmpbrd),2), |
| 77 | + 'r' = tmpbrd <- t(tmpbrd)[4:1,], |
| 78 | + 'd' = '' ) |
| 79 | + # notice that for comparison purpboses, I don't need to reorient the temp |
| 80 | + idtag[jj]<- identical(tmpbrd,squoosh(tmpbrd)$brd) |
| 81 | + } |
| 82 | + #OK, now if idtag has any FALSEs, the game ain't over. |
| 83 | + youlose <- !(FALSE%in%idtag) |
| 84 | + if(youlose) { |
| 85 | + print("Game Over") |
| 86 | + break # get out of while loop |
| 87 | + } else print("Illegal move: try again.") |
| 88 | + } else print("Illegal move: try again.") |
| 89 | +# that finished if (!length(which(brd==0 |
| 90 | +# the following "else" refers back to if (identical |
| 91 | + } else { |
| 92 | + print(brd) |
| 93 | + # add new tile. AGGGGGGGHHHHH remember what happens if the first argument |
| 94 | + # is a single integer? you get the whole damn string! use my 'cheapfix' |
| 95 | + newspot <- sample(rep(which(brd==0),2),1) |
| 96 | + brd[newspot] <- sample(c(2,4),1,prob=c(.9,.1)) |
| 97 | + print("updating...") |
| 98 | + print(brd) |
| 99 | + } #end of ifelse |
| 100 | +} #end while |
| 101 | +# might be nice to return max tile as well. Notice I don't return a brd2048-class |
| 102 | +# element 'cause we only get here when the board is full and busted. |
| 103 | +return(invisible( list(score=score, maxtile=max(brd), brd=brd) ) ) |
| 104 | +} |
| 105 | + |
| 106 | +########### crunching engine |
| 107 | +squoosh <- function(brd) { |
| 108 | + #internal score only |
| 109 | + score<-0 |
| 110 | + for (j in 1:4) { |
| 111 | + #drop column as far as possible |
| 112 | + brd[,j]<-brd[order(as.logical(brd[,j])),j] |
| 113 | + for(k in 4:2) { |
| 114 | + if(brd[k,j]==brd[(k-1),j] & brd[k,j]>0 ) { |
| 115 | + brd[(k-1):k,j]<- c(0,2*brd[k,j]) |
| 116 | + # don't drop or re-squoosh here because that could add an existing '4' to |
| 117 | + # a newly minted '2+2-->4' and that's not how it works. |
| 118 | + # every collapse adds new tile val to score |
| 119 | + score <- score + brd[k,j] |
| 120 | + } |
| 121 | + } |
| 122 | + # repeat drop (but do NOT repeat sqooshing) |
| 123 | + brd[,j]<-brd[order(as.logical(brd[,j])),j] |
| 124 | + } #end all board moves |
| 125 | + |
| 126 | +return(invisible(list(brd=brd,score=score) ) ) |
| 127 | +} |
0 commit comments