Archive for global variable

Le Monde puzzle [#875]

Posted in Kids, R, Statistics, University life with tags , , , , on July 12, 2014 by xi'an

I learned something in R today thanks to Le Monde mathematical puzzle:

A two-player game consists in A picking a number n between 1 and 10 and B and A successively choosing and applying one of three transforms to the current value of n

  • n=n+1,
  • n=3n,
  • n=4n,

starting with B, until n is larger than 999. Which value(s) of n should A pick if both players act optimally?

Indeed, I first tested the following R code

[sourcecode language=”r” gutter=”false”]
sole=function(n){
if (n>999){ return(TRUE)
}else{
return((!sole(3*n))&(!sole(4*n))&(!sole(n+1)))
}}
[/sourcecode]

which did not work because of too many calls to sole:

[sourcecode language=”r” gutter=”false”]
>sole(1)
Error: evaluation nested too deeply: infinite recursion
/ options(expressions=)?
[/sourcecode]

So I included a memory in the calls to sole so that good and bad entries of n were saved for later calls:

[sourcecode language=”r” gutter=”false”]
visit=rep(-1,1000) #not yet visited
sole=function(n){
if (n>999){ return(TRUE)
}else{
if (visit[n]>-1){ return(visit[n]==1)
}else{
visit[n]<<-((!sole(3*n))&(!sole(4*n))&
(!sole(n+1)))
return(visit[n]==1)
}}}
[/sourcecode]

Trying frontal attack

[sourcecode language=”r” gutter=”false”]
>sole(1)
Error: evaluation nested too deeply: infinite recursion
/ options(expressions=)?
[/sourcecode]

did not work, but one single intermediary was sufficient:

[sourcecode language=”r” gutter=”false”]
> sole(500)
[1] FALSE
> for (i in 1:10)
+ print(sole(i))
[1] FALSE
[1] FALSE
[1] FALSE
[1] TRUE
[1] FALSE
[1] TRUE
[1] FALSE
[1] FALSE
[1] FALSE
[1] FALSE
[/sourcecode]

which means that the only winning starters for A are n=4,6. If one wants the winning moves on top, a second counter can be introduced:

[sourcecode language=”r” gutter=”false”]
visit=best=rep(-1,1000)
sole=function(n){
if (n>999){ return(TRUE)
}else{
if (visit[n]>-1){ return(visit[n]==1)
}else{
visit[n]<<-((!sole(3*n))&(!sole(4*n))&
(!sole(n+1)))
if (visit[n]==0) best[n]<<-max(
3*n*(sole(3*n)),
4*n*(sole(4*n)),
(n+1)*(sole(n+1)))
return(visit[n]==1)
}}}
[/sourcecode]

From which we can deduce the next values chosen by A or B as

[sourcecode language=”r” gutter=”false”]
> best[1:10]
[1] 4 6 4 -1 6 -1 28 32 36 40
[/sourcecode]

(where -1 means no winning choice is possible).

Now, what is the R trick I learned from this toy problem? Simply the use of the double allocation symbol that allows to change global variables within functions. As visit and best in the latest function. (The function assign would have worked too.)