Change variable until it's right (if, else)

Go To StackoverFlow.com

-2

I run an irc bot, written in ruby, running the cinch irc framework. The bot replies with interesting facts and cycles through these facts so you won't get bored of them. I have set a cool down, so they can't be shown for 6 hours. Instead of showing the facts it first showed, it now shows randomly selected ones, which could be the ones that have been shown earlier.

line = IO.readlines("facts.txt")
factnumber = rand(line.length)
    if fact_not_next_6_hours[factnumber] == true
    factnumber = rand(line.length)
    m.reply "fact #{factnumber}: #{line[factnumber]}"
    fact_not_next_6_hours[factnumber] = true

fact_not_next_6_hours[factnumber] is the variable for the 6 hour cool down; if it's set to true, cool down is active. I need to do:

factnumber = rand(line.length) 

until it gets one that dosen't have the 6 hour cool down set to true, and then do

m.reply "fact #{factnumber}: #{line[factnumber]}"
fact_not_next_6_hours[factnumber] = true

My first idea was to do multiple ifs, but it didn't work and I'm sure there is a better way.

2012-04-05 15:10
by qwerty1911


1

You can do:

factnumber = rand(line.length)
while fact_not_next_6_hours[factnumber] == true
  factnumber = rand(line.length)
end
m.reply "fact #{factnumber}: #{line[factnumber]}"
fact_not_next_6_hours[factnumber] = true

Or:

nil while fact_not_next_6_hours[factnumber = rand(line.length)] == true
m.reply "fact #{factnumber}: #{line[factnumber]}"
fact_not_next_6_hours[factnumber] = true
2012-04-05 15:17
by Guilherme Bernal
That seems to work! Thanks. I went with the 2nd solution, its so clean and nic - qwerty1911 2012-04-05 15:24
if all the facts are used, this will end up in an infinite loo - psyho 2012-04-05 15:36
I am aware of the infinite loop, but the channel has around 680 facts so it should be ok. i also plan on adding an "instant un-cooldown - qwerty1911 2012-04-05 15:50
I'm not sure I'd use "clean and nice" to describe this code - Andrew Marshall 2012-04-05 16:07


1

You should really rename line to lines, as it is in fact an array of lines. I've done so in my answer.

This is essentially a "do while" loop:

begin 
  factnumber = rand(lines.length)
end while fact_not_next_6_hours[factnumber]

But depending on how many facts you have and how many you expect to be "used", filtering out the ones you can't use first may make more sense:

fact = (0...lines.length).zip(lines).reject do |k, v|
  fact_not_next_6_hours[k]
end.sample

m.reply "fact #{fact[0]}: #{fact[1]}"

The first bit of that ((0...lines.length).zip(lines)) is just associating each of the lines with a number (e.g. [[0, "fact"], [1, "afact"], ...]). I recommend running each part of the method chain individually so you can fully understand what's happening.

2012-04-05 15:21
by Andrew Marshall


1

First of all, if you just set a boolean flag, how will you know when to "unfreeze" it? I'd keep the "timestamp" of last accessed time in the object. Also, instead of using primitive types all around, I'd do it in a bit more object oriented fashion.

Here's my solution:

class Fact
  attr_reader :text

  def initialize(text)
    @text = text
    @last_accessed = Time.new(0) # a long time ago, not in cooldown
  end

  def in_cooldown?
    Time.now - @last_accessed < 60*60*6
  end

  def cooldown!
    @last_accessed = Time.now
  end
end

class Facts
  attr_reader :all

  def initialize(file_name)
    @all = IO.readlines("facts.txt").map{|line| Fact.new(line)} 
  end
end

class FactRandomizer
  def initialize(facts)
    @facts = facts
  end

  def get
    fact = not_in_cooldown.sample || all.sample # all can be in cooldown
    fact.cooldown!
    fact.text
  end

  private

  def not_in_cooldown
    @facts.select{|fact| !fact.in_cooldown?}
  end
end

Usage:

facts = Facts.new("whatever").all
randomizer = FactRandomizer.new(facts)
randomizer.get

EDIT:

I refactored the code, so that it does not use class methods anymore. Note, how much easier it would be to test this code now and how easy it is to interchange parts of it (like for example replacing the part that reads the facts from file or what does it mean for a fact to be in cooldown).

2012-04-05 15:31
by psyho
Can I easily change out the facts.txt to #{m.channel} ? Just thinking because its a global variable, and i put facts.txt when describing this thing for eas - qwerty1911 2012-04-05 15:58
Ads