bonsai
2014-08-20 04:53:59
Some more code for review/input. This is my current break library.
The code below will compile and run an example. It doesn't need smart/runescape. Since it takes days to cycle through logic, you need to play with the times to run sensible tests.
What is it?
It's a set of functions to handle breaks. A global instance of the break handler is defined (breakTimer) but the scripter could instantiate one per player.
Three break styles are supported, depending on which initializer gets called.
[INDENT][table="width: 500"]
[tr]
[td]Suicide[/td]
[td]Takes no breaks.[/td]
[/tr]
[tr]
[td]Normal[/td]
[td]Plays for a length of time and sleeps for a length of time (with some variance for randomization)[/td]
[/tr]
[tr]
[td]Human[/td]
[td]Uses normal style but also has start and end times for weekdays and weekends. The script will sleep outside of these hours.[/td]
[/tr]
[/table][/INDENT]
The check4break function will sleep when appropriate but it calls a user supplied procedure before and after sleeping so the script can manage what it needs to. If there are more active players in the players array it will switch players instead of sleeping.
Example usage:
Interface:
Code
The code below will compile and run an example. It doesn't need smart/runescape. Since it takes days to cycle through logic, you need to play with the times to run sensible tests.
What is it?
It's a set of functions to handle breaks. A global instance of the break handler is defined (breakTimer) but the scripter could instantiate one per player.
Three break styles are supported, depending on which initializer gets called.
[INDENT][table="width: 500"]
[tr]
[td]Suicide[/td]
[td]Takes no breaks.[/td]
[/tr]
[tr]
[td]Normal[/td]
[td]Plays for a length of time and sleeps for a length of time (with some variance for randomization)[/td]
[/tr]
[tr]
[td]Human[/td]
[td]Uses normal style but also has start and end times for weekdays and weekends. The script will sleep outside of these hours.[/td]
[/tr]
[/table][/INDENT]
The check4break function will sleep when appropriate but it calls a user supplied procedure before and after sleeping so the script can manage what it needs to. If there are more active players in the players array it will switch players instead of sleeping.
Example usage:
procedure userBreakStart(); begin end;
procedure userBreakEnd(); begin end;
breakTimer.init('1730','2245' {weekday start-end}, '0800', '2200' {weekend start-end},
20 {start-end variance}, 90 {session len}, 10 {session variance},
25 {break len}, 5 {variance}, true, userBreakStart, userBreakEnd);
...
while (true) do
begin
...
breakTimer.check4break();
end;
Interface:
type
TBreakTimer = record
...
end;
var
breakTimer: TBreakTimer;
function TBreakTimer.calcNextBreakTime(): Int64;
function TBreakTimer.msecUntilBreak(): integer;
function TBreakTimer.secUntilBreak(): integer;
function TBreakTimer.minUntilBreak(): integer;
function TBreakTimer.check4break(): boolean;
function TBreakTimer.init(): boolean;
function TBreakTimer.init(avgSession: int64;
sessVariance: int64;
avgBreak: int64;
brkVariance: int64;
userBreakStart: procedure;
userBreakEnd: procedure): boolean; overload;
function TBreakTimer.init(wdsHHMM: string; // weekday start time
wdeHHMM: string; // weekday end time
wesHHMM: string; // weekend start time
weeHHMM: string; // weekend end time
seVariance: int64; // start-end time variance
avgSession: int64; // session length (minutes)
sessVariance: int64; // session variance (minutes)
avgBreak: int64; // break length (minutes)
brkVariance: int64; // break variance (minutes)
weekendBreak: boolean; // take random long break on weekend?
userBreakStart: procedure;
userBreakEnd: procedure): boolean; overload;
Code
{$DEFINE TESTMAIN}
{$DEFINE DEBUG_ON}
// -----------------------------------------------------------------------------
// -- blBreak.simba
// -- Written by: bonsai
// -----------------------------------------------------------------------------
{$IFDEF TESTMAIN}
program blBreakTest;
{$ENDIF}
{$include_once srl-6/srl.simba}
{$f-}
{$IFNDEF TESTMAIN}
{$include_once bonsai/libupdater.simba}
{$include_once bonsai/blMisc.simba}
{$ELSE}
function daysToMsec(i: int64): Int64;
begin
result := i * 24 {hours} * 60 {minutes} * 60 {seconds} * 1000 {ms};
end;
function hoursToMsec(i : int64): Int64;
begin
result := i {hours} * 60 {minutes} * 60 {seconds} * 1000 {ms};
end;
function minToMsec(i: int64): Int64;
begin
result := i {minutes} * 60 {seconds} * 1000 {ms};
end;
function randomVary(i: integer): integer;
begin
result := randomRange(-i, i);
end;
// -----------------------------------------------------------------------------
// dayOfWeek()
//
// Internal function to calculate day of week. Sun=0, Mon=1 ... Sat=6
// -----------------------------------------------------------------------------
function dayOfWeek(mm, dd, yyyy: integer): integer;
var
mkeys: array[0..11] of integer = [1,4,4,0,2,5,0,3,6,1,4,6];
begin
// algorithm from http://www.cs.unc.edu/~livingst/DateToDay/dayofweek.c
//
mm := mm - 1;
result := (yyyy - 1900) + ((yyyy - 1900) div 4) + mkeys[mm] + dd - 1;
if ((yyyy > 1900) and (yyyy mod 4 = 0) and (mm < 2)) then
result := result - 1;
result := result mod 7;
end;
// -----------------------------------------------------------------------------
// isWeekend()
//
// Internal function to check if the specified day is on the weekend
// -----------------------------------------------------------------------------
function isWeekend(mm, dd, yyyy: integer): boolean;
var
dow: integer;
begin
result := false;
dow := dayOfWeek(mm,dd,yyyy);
if ((dow = 0) or (dow = 6)) then
result := true;
end;
// -----------------------------------------------------------------------------
// isWeekend()
//
// Internal function to check if the current day is on the weekend
// -----------------------------------------------------------------------------
function isWeekend(): boolean; overload;
var
dateStr: string;
mm, dd, yyyy: integer;
begin
result := false;
dateStr := theDate(DATE_MONTH);
mm := strToInt(copy(dateStr,1,2));
dd := strToInt(copy(dateStr,4,2));
yyyy := 2000 + strToInt(copy(dateStr,7,2));
result := isWeekend(mm,dd,yyyy);
end;
// -----------------------------------------------------------------------------
// timeOfDayToMsec()
//
// Internal function to parse the current time into hours and minutes
// Converts time to 24 hour format.
// -----------------------------------------------------------------------------
function timeOfDayToMsec() : int64;
var
hh, mm, ss: integer;
timeStr: string;
amPm: string;
begin
timeStr := theTime();
hh := strToInt(copy(timeStr,1,2));
mm := strToInt(copy(timeStr,4,2));
ss := strToInt(copy(timeStr,7,2));
amPm := copy(timeStr,10,2);
if ((hh = 12) and (amPm = 'AM')) then
hh := 0
else
if ((hh <> 12) and (amPm = 'PM')) then
hh := hh + 12;
result := ((hh * 60 {min} * 60 {sec}) + (mm * 60 {sec}) + ss) * 1000 {msec};
end;
{$ENDIF}
const
blBreakVersion = '1.0';
blBreakVerUrl = 'http://pastebin.com/raw.php?i=JdrZb32W';
blBreakCodeUrl = 'http://pastebin.com/raw.php?i=JDnHLcrq';
type
TBreakType = (BRK_SUICIDE, BRK_BASIC, BRK_HUMAN);
TBreakTimer = record
breakType : TBreakType;
onBreakStart : procedure;
onBreakEnd : procedure;
nextScheduledBreak : Int64; // offset from getSystemTime()
averageSession : int64; // minutes
sessionVariance : int64; // minutes
averageBreak : int64; // minutes
breakVariance : int64; // minutes
weekdayStart : int64; // msec since midnight
weekdayEnd : int64; // msec since midnight
weekendStart : int64; // msec since midnight
weekendEnd : int64; // msec since midnight
startEndVariance : int64; // minutes
longWeekendBreakFlag: boolean;
end;
// -----------------------------------------------------------------------------
// Global variable for users to use in the scripts
// -----------------------------------------------------------------------------
var
breakTimer: TBreakTimer;
// -----------------------------------------------------------------------------
// calcNextBreakTime()
//
// Internal function to calculate the next time we will take a break
// -----------------------------------------------------------------------------
function TBreakTimer.calcNextBreakTime(): Int64;
begin
if (self.breakType = TBreakType.BRK_SUICIDE) then
exit;
result := getSystemTime() + ( (averageSession * 60000) +
randomRange( -(self.sessionVariance * 60000),
(self.sessionVariance * 60000)));
{$IFDEF DEBUG_ON}
writeln('***** TBreakTimer: Next break time calculated, [',
msToTime((result - getSystemTime()), TIME_BARE), '] from now');
{$ENDIF}
end;
// -----------------------------------------------------------------------------
// msecUntilBreak()
//
// Returns how long until we are scheduled to take a break
// -----------------------------------------------------------------------------
function TBreakTimer.msecUntilBreak(): integer;
begin
result := nextScheduledBreak - getSystemTime();
end;
// -----------------------------------------------------------------------------
// secUntilBreak()
//
// Returns how long until we are scheduled to take a break
// -----------------------------------------------------------------------------
function TBreakTimer.secUntilBreak(): integer;
begin
result := round(self.msecUntilBreak() / 1000);
end;
// -----------------------------------------------------------------------------
// minUntilBreak()
//
// Returns how long until we are scheduled to take a break
// -----------------------------------------------------------------------------
function TBreakTimer.minUntilBreak(): integer;
begin
result := round(self.secUntilBreak() / 60);
end;
// -----------------------------------------------------------------------------
// check4break()
//
// Main function. Checks to see if it is time to take a break. If it is
// break time, calls the user specified 'pre-break' routine, then sleeps
// for the appropriate time. When it wakes up it calls the user specified
// post-break function.
// -----------------------------------------------------------------------------
function TBreakTimer.check4break(): boolean;
var
breakMs, nowTime, startTime, endingTime: int64;
adjusted: TBreakTimer;
timeToSleep: boolean;
begin
if (self.breakType = TBreakType.BRK_SUICIDE) then
exit;
timeToSleep := false;
if (self.breakType = TBreakType.BRK_HUMAN) then
begin
nowTime := timeOfDayToMsec();
if (isWeekend()) then
begin
startTime := self.weekendStart + randomVary(self.startEndVariance);
endingTime := self.weekendEnd + randomVary(self.startEndVariance);
end
else
begin
startTime := self.weekdayStart + randomVary(self.startEndVariance);
endingTime := self.weekdayEnd + randomVary(self.startEndVariance);
end;
// we have two cases to worry about.
// simple: 0 < start time < end time < 24
// overlap: 24/0 < end time < start time (start at 8pm play till 4am)
if (startTime < endingTime) then
begin
if (nowTime < startTime) then
begin
breakMs := startTime - nowTime + 100;
timeToSleep := true;
{$IFDEF DEBUG_ON}
writeln('***** TBreakTimer: Not time to play yet, sleep for [', msToTime(breakMs, TIME_BARE), ']');
{$ENDIF}
end;
if (nowTime > endingTime) then // its time for bed
begin
breakMs := (hoursToMsec(24) - nowTime) + startTime;
timeToSleep := true;
{$IFDEF DEBUG_ON}
writeln('***** TBreakTimer: Past time to play, sleep for [', msToTime(breakMs, TIME_BARE), ']');
{$ENDIF}
end;
end
else // we have the weird case with date overlap
begin
if ((nowTime < startTime) and (nowTime > endingTime)) then
begin
breakMs := startTime - nowTime + 100;
timeToSleep := true;
{$IFDEF DEBUG_ON}
writeln('***** TBreakTimer: We are outside of playtime, sleep for [', msToTime(breakMs, TIME_BARE), ']');
{$ENDIF}
end;
end;
end;
if ((not timeToSleep) and (getSystemTime() >= self.nextScheduledBreak)) then
begin
breakMs := minToMsec(self.averageBreak) + randomVary(self.breakVariance);
timeToSleep := true;
{$IFDEF DEBUG_ON}
writeln('***** TBreakTimer: It is break time, sleep for [', msToTime(breakMs, TIME_BARE), ']');
{$ENDIF}
end;
if (timeToSleep) then
begin
self.onBreakStart();
if (players.getActive() > 1) then // there is another player to run
players.next()
else
sleep(breakMs);
self.nextScheduledBreak := self.calcNextBreakTime();
self.onBreakEnd();
end;
end;
// -----------------------------------------------------------------------------
// init()
//
// Initializer. This one takes no parameters and will set things for
// BRK_SUICIDE style (no breaks at all).
// -----------------------------------------------------------------------------
function TBreakTimer.init(): boolean;
begin
self.breakType := TBreakType.BRK_SUICIDE;
result := true;
end;
// -----------------------------------------------------------------------------
// init()
//
// Initializer. This one takes the relevant parameters for the BRK_BASIC break
// style. Script will run for XX minutes (with a variance) and take breaks
// for YY minutes (again with a variance).
// -----------------------------------------------------------------------------
// initializer for basic break system
function TBreakTimer.init(avgSession: int64;
sessVariance: int64;
avgBreak: int64;
brkVariance: int64;
userBreakStart: procedure;
userBreakEnd: procedure): boolean; overload;
begin
self.breakType := TBreakType.BRK_BASIC;
self.averageSession := avgSession;
self.sessionVariance := sessVariance;
self.averageBreak := avgBreak;
self.breakVariance := brkVariance;
self.onBreakStart := userBreakStart;
self.onBreakEnd := userBreakEnd;
self.nextScheduledBreak := self.calcNextBreakTime();
end;
// -----------------------------------------------------------------------------
// init()
//
// Initializer. This one takes the relevant parameters for the BRK_HUMAN break
// style. User sets playtime hours for weekdays and weekends along with
// variances for randomization.
// -----------------------------------------------------------------------------
// initializer for human break system
function TBreakTimer.init(wdsHH: int64;
wdsMM: int64;
wdeHH: int64;
wdeMM: int64;
wesHH: int64;
wesMM: int64;
weeHH: int64;
weeMM: int64;
seVariance: int64;
avgSession: int64;
sessVariance: int64;
avgBreak: int64;
brkVariance: int64;
weekendBreak: boolean;
userBreakStart: procedure;
userBreakEnd: procedure): boolean; overload;
begin
self.breakType := TBreakType.BRK_HUMAN;
self.weekdayStart := hoursToMsec(wdsHH) + minToMsec(wdsMM);
self.weekdayEnd := hoursToMsec(wdeHH) + minToMsec(wdeMM);
self.weekendStart := hoursToMsec(wesHH) + minToMsec(wesMM);
self.weekendEnd := hoursToMsec(weeHH) + minToMsec(weeMM);
self.startEndVariance := seVariance;
self.averageSession := avgSession;
self.sessionVariance := sessVariance;
self.averageBreak := avgBreak;
self.breakVariance := brkVariance;
self.longWeekendBreakFlag := weekendBreak;
self.onBreakStart := userBreakStart;
self.onBreakEnd := userBreakEnd;
self.nextScheduledBreak := self.calcNextBreakTime();
// we call this in the initializer because it may not be time to
// start playing for the day. We will immediately go into break
self.check4break();
end;
// -----------------------------------------------------------------------------
// init()
//
// Initializer. This one takes the relevant parameters for the BRK_HUMAN break
// style. User sets playtime hours for weekdays and weekends along with
// variances for randomization.
// -----------------------------------------------------------------------------
// initializer for human break system
function TBreakTimer.init(wdsHHMM: string; // weekday start time
wdeHHMM: string; // weekday end time
wesHHMM: string; // weekend start time
weeHHMM: string; // weekend end time
seVariance: int64; // start-end time variance
avgSession: int64; // session length (minutes)
sessVariance: int64; // session variance (minutes)
avgBreak: int64; // break length (minutes)
brkVariance: int64; // break variance (minutes)
weekendBreak: boolean; // take random long break on weekend?
userBreakStart: procedure;
userBreakEnd: procedure): boolean; overload;
begin
self.init(strToInt(copy(wdsHHMM, 1, 2)), strToInt(copy(wdsHHMM, 3, 2)),
strToInt(copy(wdeHHMM, 1, 2)), strToInt(copy(wdeHHMM, 3, 2)),
strToInt(copy(wesHHMM, 1, 2)), strToInt(copy(wesHHMM, 3, 2)),
strToInt(copy(weeHHMM, 1, 2)), strToInt(copy(weeHHMM, 3, 2)),
seVariance, avgSession, sessVariance, avgBreak, brkVariance,
weekendBreak, userBreakStart, userBreakEnd);
end;
{$IFDEF TESTMAIN}
procedure printSleep();
begin
writeln('This is from the user supplied onBreakStart function');
writeln('Going to sleep. Current time is [', theTime(), ']');
end;
procedure printWake();
begin
writeln('This is from the user supplied onBreakEnd function');
writeln('Time to run. Current time is [', theTime(), ']');
end;
var
cmin: integer;
begin
breakTimer.init('2007','0349', '0800', '2200', 3, 5, 1, 5, 1, true, printSleep, printWake);
cmin := breakTimer.minUntilBreak();
while (true) do
begin
breakTimer.check4break();
sleep(5000);
if (cmin <> breakTimer.minUntilBreak()) then
begin
writeln('.. still working. Current time is [', theTime(), ']');
cmin := breakTimer.minUntilBreak();
end;
end;
end.
{$ELSE}
// -----------------------------------------------------------------------------
// initializer
//
// Sets the initial state to BRK_SUICIDE to initialize variables.
// Checks for online updates.
// -----------------------------------------------------------------------------
begin
// set it by default to BRK_SUICIDE
breakTimer.init();
updater.check4update('blBreak.simba', blBreakVersion,
blBreakVerUrl, blBreakCodeUrl, true);
end;
{$ENDIF}