Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Daily Actions

by Spidy (Chaplain)
on May 17, 2007 at 14:53 UTC ( #616020=perlquestion: print w/replies, xml ) Need Help??
Spidy has asked for the wisdom of the Perl Monks concerning the following question:

Greetings, fellow monks.

I am currently working on an online game, where we need to limit users to performing so many actions per day, using a turns system. We are using a MySQL database to store their turns remaining, and they lose a turn each time that they perform an action. However, I want to make it so that they regain some amount(5?) turns each new day...does anyone know of a way that I could do this? I thought of using cron, but I'm not sure my web host would look favorably on that, and would like a solution that I can tweak directly in my Perl. My best idea thus far has been to use localtime() and somehow compare the year, month, and date.



Basically, what I've figured out that I need to do is compare the last time that they visited, by the year then month then day, in order to figure out if there's a difference large enough to give them their new turn allotment. While it would be sweet to do this with cron(and much easier, definitely), I'm looking for a solution using Perl. The solution I'm currently considering is just storing a user's last year/month/day of an action, and then comparing that to what's returned by localtime(). What are your thoughts?

Replies are listed 'Best First'.
Re: Daily Actions
by kyle (Abbot) on May 17, 2007 at 15:14 UTC

    You could store, for each user, a date when they last received new turns. If they try to use a turn when they don't have one, check the date. If they're due to get new turns, add them to the turn count and update the date.

    You could also store the dates of all of the user's last turns taken. When the user tries to use a turn, delete all the records that are over a day old. If there are still too many turns used, disallow the turn. This gives a slightly different turn allowance, though. It's not x turns every day but x turns in any day-long period.

    Update to expand on that second idea a bit (since roboticus likes it): I recall years ago a couple of friends in a turn-based game would make a killing by waiting until the end of the "day" to take all their turns, then wait for the new turns to arrive shortly after, and take all their turns again. By doing this, they could double their effect in a short time. A "turns in time period" approach would defeat that strategy. I don't know anything about Spidey's game, so it may be the case that this "last minute, first minute" approach doesn't really gain the player any advantage.

    The down side comes for a user who tries to play at the same time every day. Let's say the player arrives at noon, takes all turns, and returns the next day. The player has to wait for a minute after noon to play again. Every day, the time when play is allowed moves later. This also means that I can't play one afternoon and then play again the next morning.

    Perhaps a better solution is a mix of some kind.

    The main problem I have with the first approach (all turns arrive at a fixed time every day) is that it might not work well for people in other time zones. If I were playing a game where turns arrive at noon, I'd have to play either in the morning or in the afternoon every day.

    Anyway, I'm rambling a lot more than I meant to (and not even with code!).


      ++ I really like your second method. If Spidy's game would benefit from frequent visits, that might make it a bit more compelling, as turns wouldn't arrive in larger/less frequent "bunches".


Re: Daily Actions
by roboticus (Chancellor) on May 17, 2007 at 15:28 UTC

    I'm not a MySQL maven, so I'm going to pretend that you said "Sybase" and leave the conversion effort as an exercise for the reader.... 8^)

    First, using your basic idea, you could (on login) compute the number of turns they get for the day. (I'd put a maximum on it, so if they don't log in for a long time they don't get too many turns for a day.) It seems like an appropriate task for the database, so you could do something like this. Given tables something like:

    create table users ( user_id varchar(10) primary key, ... --standard junk you already have here turns_left int default 0, last_turn datetime default getdate() ) create table misc ( tag varchar(32) primary key, val varchar(128) ) go insert misc (tag, val) values ('Turns_Per_Day', '5') insert misc (tag, val) values ('Max_Turns_Allowed', '15')
    You could use the following procedure when they log into the system:

    create proc compute_turns_left @user_id varchar(10) as declare @days integer, @turns, @turns_per_day, @max_turns -- Read the configuration variables select @turns_per_day = isnull(convert(int, val), 1) from misc where tag='Turns_Per_Day' select @max_turns = isnull(convert(int, val), 1) from misc where tag='Max_Turns_Allowed' -- How many days since they last used a turn? select @days=datediff(d,getdate(),last_turn) from users where user_id=@user_id -- Update their turns update turns_left = turns_left + @days * @turns_per_day from users where user_id=@user_id -- And apply the limit cap update turns_left = @max_turns from users where user_id=@user_id and turns_left > @max_turns go
    and this one every time they take a turn:
    create proc consume_turn @user_id varchar(10) as update users set turns_left = turns_left-1, last_turn=getdate() where user_id=@user_id go
    I hope you find this useful.


Re: Daily Actions
by jhourcle (Prior) on May 17, 2007 at 15:30 UTC

    The simplist way is from cron, or similar

    update table set turns = turns+ x; update table set turns = max where turns > max; commit;

    As a next option, if you don't have people logged on for days at a time, you can just give them their turns on login -- keep track of their last login date, and when they log in, give them (turns_per_day * (datediff(systime(), last_login))).

    update table set last_login = sysdate(), turns_left = ( $turns_per_day * datediff( sysdate(), last_login )) where user_id = ?

    update:: bah ... the second example didn't take into consideration order of operations:

    update table set turns_left = ( $turns_per_day * datediff( sysdate(), last_login )) +, last_login = sysdate() where user_id = ?

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://616020]
Approved by marto
LanX Ladies and gentlemen: due to shortages of "Body of Christ" we have to resort to Body of Monks ...
LanX ... buon appetito!
[LanX]: Pacific Crest Trail is really hard stuff
[Eily]: erix he plans to go as far as leuca
[erix]: ah, that's really down at the heel point :)
[Eily]: LanX how dare you imply that I made a typo? It's true but still!
[Eily]: or is it a typo if the mistake was in my brain rather than in the process of typing?
[LanX]: they were talking about meatspace recently ...
[choroba]: a "thinko"
[erix]: my app (google, really) makes that 1530 km...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (7)
As of 2017-12-13 15:16 GMT
Find Nodes?
    Voting Booth?
    What programming language do you hate the most?

    Results (369 votes). Check out past polls.