I have the following code:
first.moves <- function()
{
go.first <- readline("Do you want to go first? (Y/N) ")
if (go.first == "Y" || go.first == "y")
{
game <- altern.moves()
}
else
{
game <- move(game,1,1)
}
return(game)
}
altern.moves <- function()
{
plyr.mv <- as.numeric(readline("Please make a move (1-9) "))
game <- move(game,plyr.mv,0)
cmp.mv <- valid.moves(game)[1]
game <- move(game,cmp.mv,1)
return(game)
}
#game
game <- matrix(rep(NA,9),nrow=3)
print("Let's play a game of tic-tac-toe. You have 0's, I have 1's.")
(game <- first.moves())
repeat
{
game <- altern.moves()
print(game)
}
When I run the part after #game in batch mode neither does R stop to wait for "Do you want to go first? (Y/N)" nor does it repeat the repeat block. Everything works fine on its own and when I click through it line-by-line.
What am I doing wrong and how can I remedy the situation to have a decent program flow but with user interaction? (or do I really have to click through this part of the code line-by-line? I hope not...)
Add this to the beginning of your code:
if (!interactive()) {
batch_moves <- list('Y', 5, 2) # Add more moves or import from a file
readline <- (function() {
counter <- 0
function(...) { counter <<- counter + 1; batch_moves[[counter]] }
})()
}
Now you get
> readline()
[1] "Y"
> readline()
[1] 5
> readline()
[1] 2
EDIT: Optionally, to clean up (if you are running more scripts), add rm(readline) to the end of your script.
EDIT2: For those who don't like <<-, replace counter <<- counter + 1 with assign('counter', counter + 1, envir = parent.env(environment())).
Related
I need to create a vector with multiple inputs (integers) from user.
The intent is to create a list and verify if it has a mode and where is its median.
I am using this code:
ReadVector <- function()
{
x <- 0
while(x<16) {
n <- readline(prompt="Input one integer: ")
return(as.integer(n))
VectorUser <- c(n)
x <- x+1
}
print(VectorUser)
}
ReadVector()
And I can only get one integer, I dont know if my mistake is in the while loop or(and) in the concatenate command after it. Can you help me?
Does this work for you?
ReadVector <- function()
{
x <- 0
myvector = vector()
while(x<16) {
n <- readline(prompt="Input one integer: ")
myvector = c(myvector,n)
x <- x+1
}
return (as.integer(myvector))
}
You need yo save your values in a vector, and keep it (without returning inside the loop), until you completed it.
Hope it helps
ff=function(){
d=c()
while (TRUE){
int = readline('ENTER to quit > ')
if(nchar(int)==0) {
if(length(d)>0)cat("The numbers you entered are:",d)
else(cat("You did not enter any number!!"));break}
else{
value=suppressWarnings(as.integer(int))
if(!is.na(value)){cat(value);d=c(d,value)} else cat(ran[sample(6,1)])
}}
ff()
Is it possible to write a function in R which will hold its execution, giving the users control over the console (while in interactive mode of course), meanwhile recording their inputs, and continuing execution either:
after a certain input has been made
or after a certain output has been made
or a certain duration of time has passed
Example: ask the user a question (without using readline() for the answer)
question <- function() {
message("How much is 2 + 2?")
#let users take control of the console
#continue to next statement only if they input "2+2", or "4" or a minute has passed
#meanwhile record their last input similar to ".Last.Value", e.g.:
startTime <- Sys.time()
timeout <- FALSE
lastInput <- lastInput()
while (eval(parse(text = lastInput)) != 4 & !timeout) {
if (difftime(Sys.time(), startTime, units = "mins") > 1) {
timeout <- TRUE
}
lastInput <- lastInput()
}
if (timeout) {
stop("Sorry, timeout.")
} else {
message("Correct! Let's continue with this function:")
}
}
Where lastInput() is a function which "listens" to user input when it changes.
Obviously the above structure is tentative and won't give me what I want, some way to "listen" or "observe" and only react when the user inputs something to the console.
The final user experience should be:
> question()
How much is 2+2?
> #I'm the user, I can do whatever
> head(mtcars)
> plot(1:10)
> 3
> 2 + 2
[1] 4
Correct! Let's continue with this function:
Am I too optimistic or is there some R magic for this?
Thanks to #parth I have looked at swirl's source code and got acquainted with the addTaskCallback function. From the help file:
addTaskCallback registers an R function that is to be called each time a top-level task is completed.
And so we can make R check the users input ("top-level task") with a specific function, responding accordingly.
But since the swirl code is very "heavy", I think I need to supply a minimal example:
swirllike <- function(...){
removeTaskCallback("swirllike")
e <- new.env(globalenv())
e$prompt <- TRUE
e$startTime <- Sys.time()
cb <- function(expr, val, ok, vis, data=e){
e$expr <- expr
e$val <- val
e$ok <- ok
e$vis <- vis
# The result of f() will determine whether the callback
# remains active
return(f(e, ...))
}
addTaskCallback(cb, name = "swirllike")
message("How much is 2+2?")
}
OK, so the swirllike function evokes the 2+2 question, but it also declares a new environment e with some objects the user needs not know. It then adds the swirllike task callback to the task callback list (or rather vector). This "task callback" holds the cb function which calls the f function - the f function will run with every input.
If you run this, make sure you see the swirllike task callback with:
> getTaskCallbackNames()
[1] "swirllike"
Now the f function is similar to my sketch in the question:
f <- function(e, ...){
if (e$prompt) {
if (difftime(Sys.time(), e$startTime, units = "mins") > 1) {
timeout <- TRUE
stop("Sorry, timeout.")
}
if(!is.null(.Last.value) && .Last.value == 4) {
message("Correct! Let's continue with this function:")
e$prompt <- FALSE
while (!e$prompt) {
#continue asking questions or something, but for this example:
break
}
}
}
return(TRUE)
}
And don't forget to remove the swirllike task callback with:
removeTaskCallback("swirllike")
I want to make a program in which user will be asked to enter the location and based on that location value it should run a particular set of codes. It should wait until user enter the value of location.
readinteger <- function()
{
n <- readline(prompt="Enter your location: ")
n <- as.integer(n)
if (is.na(n))
return(as.integer(n))
}
LC <- readinteger()
if ( LC== 1)
{
print(x)
}
else if ( LC == 2)
{
print(y)
}
else
print(z)
But here it proceeds to if loop directly and then ask to enter the location
This will work fine if you include the if statements to control printing in your readinteger function. That way, readline will behave as expected (wait for input from the user) and then automatically move on to the printing commands.
readinteger <- function()
{
n <- readline(prompt="Enter your location: ")
n <- as.integer(n)
x <- "You are at location one."
y <- "You are at location two."
z <- "You are lost."
if ( n == 1)
{
print(x)
}
else if ( n == 2)
{
print(y)
}
else
print(z)
}
readinteger()
You had a if (is.na(n)) in your code that wasn't doing anything, but my guess is you want to include a check to make sure the user has provided valid input. If so, you may find a while loop helpful, so the user can correct their input if there's an error. For example:
readinteger <- function()
{
n <- NULL
while( !is.integer(n) ){
n <- readline(prompt="Enter your location: ")
n <- try(suppressWarnings(as.integer(n)))
if( is.na(n) ) {
n <- NULL
message("\nYou must enter an integer. Please try again.")
}
}
x <- "You are at location one."
y <- "You are at location two."
z <- "You are lost."
if ( n == 1)
{
print(x)
}
else if ( n == 2)
{
print(y)
}
else
print(z)
}
readinteger()
Ok. I think it's got something to do with running the whole file at one go.
It will work if you run it in Rsudio and run one step at a time, i.e., interactively.
According to the documentation of ?readline : `In non-interactive use the result is as if the response was RETURN and the value is "". In which case, one solution is to call the function again, as shown here : http://www.rexamples.com/4/Reading%20user%20input
I am not 100% sure it works without hitch.
For a more complex solution to your problem , you can see this question: Make readline wait for input in R
(Note: I'm adding this as answer simply for he sake of formatting. It's not really an answer )
I have a recursive function that uses the output of the previous call as the input of the next call:
recurse_foo = function(input) {
if(identical(input, character(0))) return(NULL)
else {
uu = get_incremental_output(input) ## <-- interested in collecting this
return(recurse_foo(uu))
}
}
As is evident, the terminal output is not very interesting, and I am interested in collecting the intermediate output, but I cannot imagine that growing a global list or any other side effect would be elegant (which is the only thing I can think of).
Any other abstractions that might be useful here?
Thanks.
Specific example:
final_countdown = function(input) {
if (input/2 < 1) return(NULL)
else {
uu = input/2 # <-- interested in collecting this
print(uu)
return(final_countdown(uu))
}
}
final_countdown(100)
In this case, I am interested in collecting the sequence of uus that are printed.
This is a solution, if all intermediate outputs are of the same type:
final_countdown = function(input) {
if (input/2 < 1) return(NA)
else {
c(input, final_countdown(input/2))
}
}
I have a program to execute per 15 seconds, how can I achieve this, the program is as followed:
print_test<-function{
cat("hello world")
}
What I use for executing same code block every 15 seconds:
interval = 15
x = data.frame()
repeat {
startTime = Sys.time()
x = rbind.data.frame(x, sum(data)) #replace this line with your code/functions
sleepTime = startTime + interval - Sys.time()
if (sleepTime > 0)
Sys.sleep(sleepTime)
}
x and data are dummy which you need to replace accordingly. This will execute indefinitely until stopped by user. If you need to stop and start at specific times then you need a for loop instead of 'repeat`.
Hope this helps.
You can do something like this:
print_test<-function(x)
{
Sys.sleep(x)
cat("hello world")
}
print_test(15)
If you want to execute it for a certain amount of iterations use to incorporate a 'for loop' in your function with the number of iterations.
You can use something like this:
print_test<-function(x)
{
if(condition)
{
Sys.sleep(x);
cat("hello world");
print_test(x);
}
}
print_test(15)
In this, a function is calling itself after the seconds passed as argument given the condition evaluates to true.
You also can use like this:
h <- function(i) {
Sys.sleep(i)
print("Hello world!")
}
timer <- function(i) {
while (T) {
h(i)
}
} # Timer function