Trigger a Loop to pause and continue when space bar is pressed - ruby

I want to pause the running loop when i hit space and resume it again on doing so. How do i do it?
require 'rubygems'
require 'rest-client'
URL="some url here"
data1 = 0
data2 = 0
sign = ["up","down","equal"]
i=3
while true
response = RestClient.get(URL)
arr = (response.body).split(/"/)
data2=arr[9].to_i
if data2>data1
i = 0
elsif data2<data1
i = 1
else data2 == data1
i = 2
end
puts "#{arr[9]} #{sign[i]}"
data1=arr[9].to_i #marker<<<---Here
end
Simpler saying i want the loop to come to the marker and not run again till space is pressed.
Edit
I tried putting a puts there but obviously it pauses there and waits for me to give an input every time. Please try to make things as less complex as possible. I am kind of a beginner.

Use threads? This is not a direct answer but will give you a picture of how to use them.
$key_hit = false
t1 = Thread.new{
loop{
puts "Hello"
break if $key_hit
}
}
t2 = Thread.new {
x = gets
$key_hit = true
}
t1.join
t2.join
puts "Done, exiting"

Related

Input only open for a certain time in Ruby

I try to programm Snakes with ruby.
The first problem I encountered was to get input with out pressing enter at the end all the time. Luckily I found a solution for that at How to get a single character without pressing enter?.
The problem I am stuck with now is, that I want to have the input from the user only open for a certain amount of time. In order to let the snake keep on going if no change in direction is demanded by the user.
The code I got looks like this:
system("stty raw -echo")
str = STDIN.getc
ensure
system("stty -raw echo")
end
p str.chr
case str
when "z"
velocityX = -1
velocityY = 0
when "q"
velocityY = -1
velocityX = 0
when "d"
velocityY = 1
velocityX = 0
when "s"
velocityX = 1
velocityY = 0
when "e"
puts "Bye"
on = false
else
puts "Not found"
end
x += velocityX
y += velocityY
It tried with an if command around the input but that wouldn't work. I also tried looking it up on stack overflow but it seems that no one asked that question before. The only thing I found was the the sleep() command but I seems like that can't help either.
Any help would be highly appreciated.
Use Timeout.
For example, if you want to wait 2 seconds, you could do something like this:
require 'timeout'
begin
system("stty raw -echo")
str = Timeout::timeout(2) { STDIN.getc }
rescue Timeout::Error
str = "no input"
ensure
system("stty -raw echo")
end

Storing the result of an 'x.times do' loop in a different variable upon each completion?

I have code that runs a 'do' loop a number of times set by a user input, then outputs the result of that loop.
I want to store each result in its own variable once each instance of the loop completes so I can use them later. Right now they're printed in the terminal and the program forgets them.
This is an example of the code I have so far:
input_num.times do
loop_select = rand(1..4)
loop_select = loop_select.round
if loop_select == 1
answer = answer.instance_eval{method.method.method}
set_answer = answer
elsif loop_select == 3
answer = answer.instance_eval{method.method.method}
set_answer = answer
elsif loop_select == 2
answer = answer.instance_eval{method.method.method}
set_answer = answer
elsif loop_select == 4
answer = answer.instance_eval{method.method.method}
set_answer = answer
end
set_answer = print_answer.html
puts set_answer
end
I want set_answer to be something like set_answer_1, set_answer_2, etc. for each iteration of the loop, but I can't set this as a static number because the amount of times vary for each input.
Something like this?
foo = 5
output = foo.times.map do |i|
"loop #{i}"
end
output # => ["loop 0", "loop 1", "loop 2", "loop 3", "loop 4"]
where foo is the input from the user.

Ruby code efficiency

Is there a way to make this code shorter and simpler?
loop do
if possibleSet.split(" ").map(&:to_i).any? {|e| (e<0 || e>12)}
print "Please enter valid numbers (between 1 and 12): "
possibleSet = gets
errorinput = false
else
errorinput = true
end
break if errorinput
end
Refactored a bit :)
loop do
print "Please enter valid numbers (between 1 and 12): "
possibleSet = gets.chomp
break unless possibleSet.split(" ").map(&:to_i).any? {|e| (e<0 || e>12)}
end
The code below will check input for correctness:
input = loop do
print "Please enter valid numbers (between 1 and 12): "
# ⇓⇓⇓ as many spaces as user wants
input = gets.chomp.split(/\s+/).map(&:to_i) rescue []
break input unless input.empty? || input.any? { |i| !(0..12).include? i }
end
This parses the user input in an array (not exactly the same behavior, but I hope it is cleaner and you can work from there)
set = []
until set.all? {|i| (1..11).include?(i) } && !set.empty? do
set = gets.split(' ').map(&:to_i)
end

Ruby: function/method positions

I have this factorial app that's supposed to go infinite if answer is always "y".
def continue?
answer = gets
if answer.downcase == "y"
main
elsif answer.downcase == "n"
exit
else
"This means n to me. Follow the rules next time. Bye."
end
end
def main
p "Enter any Integer"
out = gets
num = out.to_i
def factorial(num)
sum = num
(num-1).times {sum = sum * (num - 1); num = num-1}
sum
end
p factorial(num)
p "Do you want another number"
continue?
end
main
At first, #continue? was at the end of the app, but then when I called continue in #main I'd get an error for non-existing Method. So, I moved #continue? to the top but now I can't call #main because of the same method error again. I can put #continue? inside #main method but I don't think it will do a lot. Is there a better way for handling this kind of situation?
If my code is off or my practice is not the best please let me know. And I'd use #inject for factorial but I was working with ruby 1.8.5 so I had to do what I could.
First of all, calling main from another function is weird because main should only be called once when the program starts.
Second, if you do it this way you're going to run out of memory because your callstack is going to keep growing (main, continue, main continue, ...)
Why don't you make continue? return a true or false value. Then in main you can write
begin
p "Enter any Integer"
out = gets
num = out.to_i
def factorial(num)
sum = num
(num-1).times {sum = sum * (num - 1); num = num-1}
sum
end
p factorial(num)
p "Do you want another number"
end while continue?
You could put the condition in a while loop instead of calling the function every time. Also, take care with gets method, you should strip the input.
def continue?
answer = gets.strip
if answer.downcase == "y"
true
elsif answer.downcase == "n"
false
else
p "This means n to me. Follow the rules next time. Bye."
false
end
end
def main
begin
p "Enter any Integer"
out = gets
num = out.to_i
def factorial(num)
sum = num
(num-1).times {sum = sum * (num - 1); num = num-1}
sum
end
p factorial(num)
p "Do you want another number"
end while continue?
end
main
You've got a couple of problems. First, when you do answer = gets what you're getting isn't just a letter, it's a letter followed by a linefeed, e.g. 'y\n'. The solution is to use str#chomp. Also, you're not actually showing anything when a letter other than 'y' or 'n' is entered. Here's the fixed method:
def continue?
answer = gets.chomp
if answer.downcase == "y"
main
elsif answer.downcase == "n"
exit
else
puts "This means n to me. Follow the rules next time. Bye."
end
end

Stopping a thread, ensuring that certain final code is run

For this answer I wrote code like:
def show_wait_spinner
dirty = false
spinner = Thread.new{
loop{
print "*"
dirty = true
sleep 0.1
print "\b"
dirty = false
}
}
yield
spinner.kill
print "\b" if dirty
end
print "A"
show_wait_spinner{ sleep rand }
puts "B"
The goal is to ensure that the final output was "AB"—to print a final "\b" if it was not already printed by the thread. That code seems messy to me in Ruby where begin/rescue/ensure exists. So I tried some other implementations of show_wait_spinner; all of them fail to ensure that "AB" is always the output, and never "A*B" or "AB*".
Is there a cleaner, more Ruby-esque way to implement this logic?
Stop at end of loop via Mutex
def show_wait_spinner
stop = false
stopm = Mutex.new
spinner = Thread.new{
loop{
print "*"
sleep 0.1
print "\b"
stopm.synchronize{ break if stop }
}
}
yield
stopm.synchronize{ stop = true }
STDOUT.flush
end
…but my logic must be off, since this always results in "A*B".
Stop at end of loop via Thread-local variable
This second attempt results in sometimes "A*B" being printed, sometimes "AB":
def show_wait_spinner
stop = false
spinner = Thread.new{
Thread.current[:stop] = false
loop{
print "*"
sleep 0.1
print "\b"
stopm.synchronize{ break if Thread.current[:stop] }
}
}
yield
spinner[:stop] = true
STDOUT.flush
end
Kill and Ensure the Thread
def show_wait_spinner
spinner = Thread.new{
dirty = false
begin
loop{
print "*"
dirty = true
sleep 0.1
print "\b"
dirty = false
}
ensure
print "\b" if dirty
end
}
yield
spinner.kill
STDOUT.flush
end
Raise and Rescue the Thread
def show_wait_spinner
spinner = Thread.new{
dirty = false
begin
loop{
print "*"
dirty = true
sleep 0.1
print "\b"
dirty = false
}
rescue
puts "YAY"
print "\b" if dirty
end
}
yield
spinner.raise
STDOUT.flush
end
Instead of killing your thread, why don't you flip a variable that causes it to stop at a pre-defined point? If you let it cycle through and exit at the end of the loop you won't have nearly as much trouble.
For instance:
def show_wait_spinner
running = true
spinner = Thread.new do
while (running) do
print "*"
sleep 0.1
print "\b"
end
end
yield
running = false
spinner.join
end
print "A"
show_wait_spinner{ sleep rand }
puts "B"
When you call Thread#kill you have no idea where the thread is, and the thread isn't given an opportunity to clean up what it's doing. You can always kill the thread if your polite "stop running" request isn't respected.
I prefer your synchronized stop condition approach but you have a couple bugs:
after you set the stop variable, you almost immediately end the
program, so the thing that stops the thread is program exit, not the
conditional test in the loop; use Thread#join to wait for the thread
to exit normally and you'll get the consistent output you want.
break in the synchronize block breaks out of the block, not the
loop.
def show_wait_spinner
stop = false
stopm = Mutex.new
spinner = Thread.new{
loop{
print "*"
sleep 0.1
print "\b"
break if stopm.synchronize{ stop }
}
}
yield
stopm.synchronize{ stop = true }
spinner.join
STDOUT.flush
end
print "A"
show_wait_spinner{ sleep rand }
puts "B"
I would avoid any solution involving Thread#raise and Thread#kill as their behavior can never be predictable and correct, see Charles Nutter's rant about the brokenness of these methods.
The Mutex#synchronize is only necessary for this simple boolean flipping if you really care a lot about the precise timing around the race condition when the parent thread sets the var, which in this example isn't likely, so you could avoid the overhead and just set and read stop normally.
In your mutex example, you need to wait for the Thread to finish before exiting the method. Currently you set stop to true, then exit the method, print B and end your script before the spinner thread is able to wake up and print the last backspace to delete the * character.
Also, the break in stopm.synchronize{ break if stop } only exits the inner block, not the loop, so you need to use catch/throw or something.
However, you don't need the mutex. This works for me in 1.9.3:
def show_wait_spinner
exit = false
spinner = Thread.new{
loop{
print "*"
sleep 0.1
print "\b"
break if exit
}
}
yield
exit = true
spinner.join
end
Adding $stdout.sync = true at the top makes it work in 1.8.7.

Resources