views:

94

answers:

5

Hi all,

I am in charge of a website, and I have set up a "Quote of the Day" which currently is quite simplistic. See Here (on the right of the page)

What it currently does is it gets the Day of the month and the month, and normalises to one, then multiplies by the number of quotes (stored in an xml file) and rounds down. While this method will give me the same quote whichever machine I am on (something a random number generator could never do) it has been pointed out to me that this method is flawed. If you consider January the first couple quotes are going to be the same, 1*1/360, 2*1/360, 3*1/360, thus the quote isn't unique.

Can anyone think of a better way to select a quote of the day?

A: 

You could try rounding up on an even day and rounding down on an odd day. But I'm am sure there is better ways, this is just quick suggestion.

Also you could try using the current day of the year in the calculation as this is unique for each new day in the year as opposed to repeating each month.

kyndigs
A: 

Do you have to limit yourself to having a cycle of 360 days? If you have for example 500 quotes. some might never be used.
How about- Every day pick a random number between 1 and #OfQoutes, use it as the quote of day index, and mark it as "used in current cycle".
Next time when you pick a number, if you pick a quote that is marked as "used in current cycle" re-pick until you get a number of quote which isn't marked so. When all quotes are marked, un-mark all of them.
This will ensure you're going through all quotes in each cycle, together with randomness, and it will obviously work for any number of quotes.

Oren A
+1  A: 

True, determinism is something "a random number generator could never do". Fortunately (for this case, at least), programming languages provide pseudo-random number generators, not the real thing. The pseudo-random numbers are generated by doing a bunch of calculations on a "seed" value.

To get a repeatable "random" selection, then, all you need to do is set the seed in a way which is consistent for each day - I would suggest using the date, in "yyyymmdd" format, as the seed, but any other number which will be unchanged over the course of a day will work just as well.

Once you have your seed, tell the PRNG to use it with the command srand(mySeed); and you'll get the same sequence of "random" numbers from rand() every time (until mySeed changes).

Dave Sherohman
I've done exactly this on sites before. This also means you won't have the same quote on e.g. every January 1.
pjmorse
This may not help if the only language available is JavaScript, whose `Math.random()` does not support seeding.
Andrew
@Andrew: Hrmph! I was not aware of that limitation in JS's PRNG. Thanks for catching my oversight.
Dave Sherohman
Yeah, I can only use Javascript unfortunately
adustduke
+1  A: 

If you want to show the quotes in order, you could get the current Julian Day number, which will increase by one each day, and take the reminder after dividing it by the number of quotes as the number of today's quote. If you want to show all quotes but the order of them to change each cycle, you can xor the quote number and rearrange the bits using some logic that you get from the quotient of the division.

jjrv
+1  A: 

Fun question. Instead of relying on days of the month, why not count days since a given date? JS provides a pretty good property for that: getTime(), which gives you the number of milliseconds since 12am UTC on Jan. 1 1970, which you can convert to days with some simple division.

The only thing that complicates it is that if you expect your quotes to shift at midnight (and who doesn't?), you have to take into account the timezone. Again, JS provides that with getTimezoneOffset(), which gives the number of minutes ahead or behind the user's locale is compared to UTC. If you want ALL users to flip at the same time, regardless of where they live, just set this to a static value.

Your code could look something like this:

var intQuoteCount = 51; // The number of quotes in your library
var dtNow = new Date();
var intTZOffset = dtNow.getTimezoneOffset() * 60000; // automatically adjust for user timezone
var intNow = dtNow.getTime() - intTZOffset;
var intDay = Math.floor(intNow / 86400000); // The number of 'local' days since Jan 1, 1970
var intQuoteToDisplay = intDay % intQuoteCount;
Andrew
Cheers Andrew! I wasn't aware of the getTime() function
adustduke