1

I am trying to program tic-tac-toe in R - here are my two functions for making a move and evaluating all valid moves (the ones are X's, zeros are O's and NA is not taken yet):

move <- function(board,square,mark) { if (square < 1 || square > 9 || !is.na(board[square])) { return(NA) } else board[square] <- mark return(board) } valid.moves <- function(board) { return(which(is.na(board))) } 

Now setting up a test position, evaluating all valid moves and then make those moves...

test.last <- matrix(c(1,1,NA,0,NA,0,NA,0,1),nrow=3) moves <- valid.moves(test.last) move(test.last,moves,1) 

...gives a result which I didn't intend:

 [,1] [,2] [,3] [1,] 1 0 1 [2,] 1 1 0 [3,] 1 0 1 

I wanted to have three different boards with the respective valid moves (which will then be evaluated with another function whether it is a winning position) and not one board with all valid moves made at once.

I don't want to do this with a loop but the vectorization should not take place all at once 'inside' the move function but 'outside' of it - so basically I want to do the following without a loop (the eval.pos function to evaluate the position is of the form eval.pos <- function(board){}):

for (i in 1:length(moves)) { after.moves <- move(test.last,moves[i],1) print(after.moves) print(eval.pos(after.moves)) } 

How can I accomplish this without a loop?

8
  • Although, this is just a mapply, see -perhaps- something like Vectorize(move, "square", SIMPLIFY = F)(test.last, moves, 1) Commented Mar 22, 2014 at 20:31
  • which returns a length-3 vector in this case. You might have had better luck using the arr.ind=TRUE option so you could identify the matrix indices. Commented Mar 22, 2014 at 20:53
  • @IShouldBuyABoat: I tried that but I find this solution a little bit easier because you only have one number as coordinates. Commented Mar 22, 2014 at 20:55
  • If one of the answers "works" for you then you need to checkmark it. Otherwise people will assume there remains an outstanding unsolved issue. Commented Mar 22, 2014 at 21:17
  • @IShouldBuyABoat: Thank you, I am well aware how the system works ;-) Commented Mar 22, 2014 at 21:20

2 Answers 2

1
move2 <- function(board, square, mark) { lapply(square, function(x,i,value) `[<-`(x,i,value), x=board, value=mark) } 

Note that the anonymous function() is needed because [<- is primitive.

Sign up to request clarification or add additional context in comments.

5 Comments

+1: Great thank you. How can I use the output of the function directly as input for my eval.pos function which is of the form eval.pos <- function(board){}? With eval.pos(move2(test.last,moves,1)) I get the following error: Error in board[1, ] : incorrect number of dimensions
lapply returns a list; I suppose you could use it again for eval.pos also, eg lapply(X, eval.pos) with X being the result of move2
Ok, that works too. What is a little bit bulky is that one now has all these lists as containers. Do you think that there could be a solution that does the same trick without lists as with standard vectorization (which also doesn't use lists as containers)?
@vonjd like sapply?
@rawr: To be honest with you the whole 'apply' family of functions still confuses me! I just want to get a vector back of all the evaluated board positions after the respective valid moves habe been made: eval.pos(move2(test.last,moves,1))
1

Expanding my suggestion in the comment. How to use matrix indices to generate a list of move options:

 valid.moves <- function(board) { return(which(is.na(board), arr.ind=TRUE)) } > moves <- valid.moves(test.last) > moves row col [1,] 3 1 [2,] 2 2 [3,] 1 3 > lapply(1:3, function( mv) {start <- test.last start[matrix(moves[mv,],ncol=2)] <- 1 start}) [[1]] [,1] [,2] [,3] [1,] 1 0 NA [2,] 1 NA 0 [3,] 1 0 1 [[2]] [,1] [,2] [,3] [1,] 1 0 NA [2,] 1 1 0 [3,] NA 0 1 [[3]] [,1] [,2] [,3] [1,] 1 0 1 [2,] 1 NA 0 [3,] NA 0 1 

2 Comments

+1: Thank you! What I find a little bit bulky also with this solution is that one now has a list as a container. Do you think that there could be a solution that does the same trick without a list as is the case with standard vectorization (which also doesn't use lists as containers)? I just want to get a vector back of all the evaluated board positions after the respective valid moves have been made: eval.pos(move2(test.last,moves,1))
A list is the only structure that can deliver three separate matrices in a useful package. If you used sapply you would have gotten a 9 x 3 matrix which would not have seemed as natural for doing the evaluation that I'm guessing you would want to do. Or are you just creating random moves?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.