Code covered by the BSD License  

Highlights from
Coffee Roulette

image thumbnail

Coffee Roulette

by

 

13 Feb 2011 (Updated )

Let Matlab decide whose turn it is to get the coffee.

CoffeeRoulette()
% CoffeeRoulette
% 
% Adds your name to the coffee list and sends a mail to a random person,
% when he or she has to get coffee.

function CoffeeRoulette()
global Message SMTP_server_addr work_start work_end CR_dir users

%% Settings
% Set the directory in which you have placed CoffeeRoulette
CR_dir = '.';
% Define the users that can drink along
% the fieldnames should match the usename as found using
% "getenv('USERNAME')" where spaces and dashes are substituted with
% underscores. This excludes users with just a number as username, as this
% is no valid fielname in MATLAB
users.emile.email = 'foo@bar.com';
users.pete.email = 'foo2@bar.com';
% Define from what time the CoffeeRoulette should start
work_start = 8;
% Define at what time the CoffeeRoulette should end
work_end = 18;
% Define the maximum time you wish to wait for coffee
max_interval = 60;
% Define the minimum number of drinkers, before an email is sent
MinDrinkers = 2;
% Set your severs SMTP address
SMTP_server_addr = 'mail';
% Set the message subject for the email, which is sent to the fetcher
Message.title = 'You have been selected to fetch coffee!';
% Set the message body for the email, which is sent to the fetcher
Message.body = 'Please serve:';

%% The script
% Get the user who is calling the script.
thisuser = regexprep(getenv('USERNAME'),'[ -]','_');

% Check if thisuser is in the user struct
if ~any(strcmp(fieldnames(users),thisuser))
    disp('You are not in the list of coffee drinkers. Add yourself to the users structure and try again.');
    return
end

% Get the time at which the script is called
thetime = datestr(now);

% Save the old dir, so you can return to it.
old_dir = pwd;
% Change to the CoffeeRoulette dir, such that the json is found.
cd(CR_dir)
% Test if the Coffee.json file exists
dir_list = dir('Coffee.json');
if isempty(dir_list)
    Coffee.drinkers.(thisuser).thirst = 1;
    Coffee.drinkers.(thisuser).time = thetime;
    Coffee.drinkers.(thisuser).firstrequest = thetime;
    Coffee.lastrequest.time = thetime;
    Coffee.lastrequest.user = thisuser;
    Coffee.firstrequest.time = thetime;
    Coffee.firstrequest.user = thisuser;
    Coffee.previousrequest.time = thetime;
else
    fid = fopen('Coffee.json','r');
    jsonCoffee = fread(fid,'uint8=>char')';
    fclose(fid);
    Coffee = json2mat(jsonCoffee);
    if isfield(Coffee, 'previousrequest')
        if floor((datenum(thetime) - datenum(Coffee.previousrequest.time))*24) > (work_end-work_start)
            new_prev = datevec(thetime);
            new_prev(4) = work_start;
            new_prev(5) = 00;
            Coffee.previousrequest.time = new_prev;
        end
    end
    if ~isfield(Coffee, 'firstrequest')
        Coffee.firstrequest.time = thetime;
        Coffee.firstrequest.user = thisuser;
    end
    if ~isfield(Coffee,'drinkers')
        Coffee.drinkers=struct();
    end
    if ~any(strcmp(thisuser,fieldnames(Coffee.drinkers)))
            Coffee.drinkers.(thisuser).thirst = 1;
            Coffee.drinkers.(thisuser).time = thetime;
            Coffee.drinkers.(thisuser).firstrequest = thetime;
            Coffee.lastrequest.time = thetime;
            Coffee.lastrequest.user = thisuser;
    else
            Coffee.drinkers.(thisuser).thirst = Coffee.drinkers.(thisuser).thirst + 1;
            Coffee.drinkers.(thisuser).time = thetime;
            Coffee.lastrequest.time = thetime;
            Coffee.lastrequest.user = thisuser;
    end %~any(strcmp(thisuser,fieldnames(Coffee.drinkers)))
end %isempty(dir_list)

%% Check if the conditions for getting coffee are true
if eval(datestr(now,'HH')) >= work_start && eval(datestr(now,'HH')) <= work_end
    if (length(fieldnames(Coffee.drinkers)) >= MinDrinkers) ...
    || ((datenum(now) - datenum(Coffee.firstrequest.time))*24*60 > max_interval)
        Roulette(Coffee);
        Coffee = rmfield(Coffee, {'drinkers', 'lastrequest','firstrequest'});
%         Coffee.drinkers = rmfield(Coffee.drinkers, fieldnames(Coffee.drinkers));
        Coffee.previousrequest.time = thetime;
    end
elseif eval(datestr(now,'HH')) > work_end
    disp('It is too late, your coffee will come tomorrow.');
elseif eval(datestr(now,'HH')) < work_start
    disp('You are too early. Wait a little before I am awake.');
end

%% Store the Coffee variable in Coffee.json
jsonCoffee = mat2json(Coffee);
fid = fopen('Coffee.json','w');
fprintf(fid,jsonCoffee);
fclose(fid);

cd(old_dir);

function Roulette(Coffee)
    % Retrieve the global vars, Message and SMTP_server_addr
    global Message SMTP_server_addr CR_dir users
    % Get all drinkers
    drinkers = fieldnames(Coffee.drinkers);
    % Select a fetcher at random
	Fetcher = floor((length(drinkers))*rand)+1;
    % Get Fetchers email address
    email = users.(drinkers{Fetcher}).email;
    % Note who wanted Coffee
    being_served = '';
    for i = 1:length(drinkers)
        being_served = [being_served sprintf('\n%s', drinkers{i})];
    end
    if ispref('Internet')
        old_email = getpref('Internet','E_mail');
    else
        old_email = '';
    end
    % Set the SMTP server address
    setpref('Internet','SMTP_Server',SMTP_server_addr)
    setpref('Internet','E_mail','CoffeeRoulette@hotmail.com');
    % Send the mail
    sendmail(email, Message.title,[Message.body 10 being_served 10 10 'Kind Regards, CoffeeRoulette' 10 'file://' strrep(strrep(CR_dir,'\','/'), ' ','%20') '/stats.html']);
    % Show who is Fetcher to the caller of the script (More fun if this line is blanked)
    disp(['mail sent to ' email])
    setpref('Internet','E_mail',old_email);
    % Do some statistics
    do_stats(Coffee, drinkers{Fetcher}, now)


function do_stats(Coffee, Fetcher, time_served)
global work_start work_end
dir_list = dir('CoffeeStats.json');
drinkers = fieldnames(Coffee.drinkers);

max_wait = 0;
min_wait = Inf;
if isempty(dir_list)
    for i = 1:length(drinkers)
        thisuser = drinkers{i};
        [s.year s.month s.day s.hour s.minute s.second] = (datevec(time_served));
        stats.drinkers.(thisuser).time_served{1} = s;
        stats.drinkers.(thisuser).thirst(1) = Coffee.drinkers.(thisuser).thirst;
        stats.drinkers.(thisuser).days = 1;
        stats.drinkers.(thisuser).date(1) = s.year*1e4+s.month*1e2+s.day;
        stats.drinkers.(thisuser).avg_cups_a_day = 1;
        stats.drinkers.names{1} = thisuser;
        time_req = datevec(Coffee.drinkers.(thisuser).firstrequest);
        time_serv = datevec(time_served);
        if floor((datenum(time_served) - datenum(Coffee.drinkers.(thisuser).firstrequest))*24) > (work_end-work_start)
            time_req(4) = work_start;
            time_req(5) = 00;
            time_req(1:3) = time_serv(1:3);
            Coffee.drinkers.(thisuser).firstrequest = datestr(time_req);
        end
        wait = floor((datenum(time_served) - datenum(Coffee.drinkers.(thisuser).firstrequest))*24*60);
        stats.drinkers.(thisuser).time_waited{1} = wait;
        if wait >= max_wait
            stats.longestwaiting.user = thisuser;
            stats.longestwaiting.mins = wait;
            max_wait = wait;
        end
        if wait <= min_wait
            stats.shortestwaiting.user = thisuser;
            stats.shortestwaiting.mins = wait;
            min_wait = wait;
        end
        if strcmp(thisuser, Fetcher)
            stats.drinkers.(thisuser).times_fetched = 1;
        else
            stats.drinkers.(thisuser).times_fetched = 0;
        end
    end
    [s.year s.month s.day s.hour s.minute s.second] = (datevec(time_served));
    stats.serving.time(1) = s;
    stats.serving.days = 1;
    stats.serving.date(1) = s.year*1e4+s.month*1e2+s.day;
    stats.serving.hour = zeros(1,work_end-work_start);
    stats.serving.hour(s.hour-work_start+1) = 1;
    stats.serving.avg_cups_a_day = 1;
    deltaT = floor((datenum(time_served)-datenum(Coffee.previousrequest.time))*24*60);
    stats.serving.waited(1) = deltaT;
    stats.fetcher{1} = Fetcher;
else
    fid = fopen('CoffeeStats.json','r');
    jsonstats = fread(fid,'uint8=>char')';
    fclose(fid);
    stats = json2mat(jsonstats);
    for i = 1:length(drinkers)
        thisuser = drinkers{i};
        if ~isfield(stats,'drinkers')
            stats.drinkers=struct();
         end
        if ~any(strcmp(thisuser,stats.drinkers.names))
            [s.year s.month s.day s.hour s.minute s.second] = (datevec(time_served));
            stats.drinkers.(thisuser).time_served(1) = s;
            stats.drinkers.(thisuser).thirst(1) = Coffee.drinkers.(thisuser).thirst;
            stats.drinkers.(thisuser).date(1) = s.year*1e4+s.month*1e2+s.day;
            stats.drinkers.(thisuser).days = 1;
            stats.drinkers.(thisuser).avg_cups_a_day = length(stats.drinkers.(thisuser).date)/stats.drinkers.(thisuser).days;
            stats.drinkers.names{end+1} = thisuser;
            time_req = datevec(datenum(Coffee.drinkers.(thisuser).firstrequest));
            time_serv = datevec(datenum(time_served));
            if floor((datenum(time_served) - datenum(Coffee.drinkers.(thisuser).firstrequest))*24) > (work_end-work_start)
                time_req(4) = work_start;
                time_req(5) = 00;
                time_req(1:3) = time_serv(1:3);
                Coffee.drinkers.(thisuser).firstrequest = datestr(time_req);
            end
            wait = floor((datenum(time_served) - datenum(Coffee.drinkers.(thisuser).firstrequest))*24*60);
            stats.drinkers.(thisuser).time_waited(1) = wait;
            if wait >= max_wait
                stats.longestwaiting.user = thisuser;
                stats.longestwaiting.mins = wait;
                max_wait = wait;
            end
            if wait <= min_wait
                stats.shortestwaiting.user = thisuser;
                stats.shortestwaiting.mins = wait;
                min_wait = wait;
            end
            if strcmp(thisuser, Fetcher)
                stats.drinkers.(thisuser).times_fetched = 1;
            else
                stats.drinkers.(thisuser).times_fetched = 0;
            end
        else
            [s.year s.month s.day s.hour s.minute s.second] = (datevec(time_served));
            stats.drinkers.(thisuser).time_served(end+1) = s;
                stats.drinkers.(thisuser).thirst(end+1) = Coffee.drinkers.(thisuser).thirst;
            time_req = datevec(datenum(Coffee.drinkers.(thisuser).firstrequest));
            time_serv = datevec(datenum(time_served));
            if floor((datenum(time_served) - datenum(Coffee.drinkers.(thisuser).firstrequest))*24) > (work_end-work_start)
                time_req(4) = work_start;
                time_req(5) = 00;
                time_req(1:3) = time_serv(1:3);
                Coffee.drinkers.(thisuser).firstrequest = datestr(time_req);
            end
            wait = floor((datenum(time_served) - datenum(Coffee.drinkers.(thisuser).firstrequest))*24*60);
            stats.drinkers.(thisuser).time_waited(end+1) = wait;
            if ~any(stats.drinkers.(thisuser).date == s.year*1e4+s.month*1e2+s.day)
               stats.drinkers.(thisuser).days = stats.serving.days + 1;
            end
            stats.drinkers.(thisuser).date(end+1) = s.year*1e4+s.month*1e2+s.day;
            stats.drinkers.(thisuser).avg_cups_a_day = length(stats.drinkers.(thisuser).date)/stats.drinkers.(thisuser).days;
            if wait >= max_wait
                stats.longestwaiting.user = thisuser;
                stats.longestwaiting.mins = wait;
                max_wait = wait;
            end
            if wait <= min_wait
                stats.shortestwaiting.user = thisuser;
                stats.shortestwaiting.mins = wait;
                min_wait = wait;
            end
            if strcmp(thisuser, Fetcher)
                stats.drinkers.(thisuser).times_fetched = stats.drinkers.(thisuser).times_fetched + 1;
            end
        end %~any(strcmp(thisuser,fieldnames(stats.drinkers)))
    end
    [s.year s.month s.day s.hour s.minute s.second] = (datevec(time_served));
    stats.serving.time(end+1) = s;
    if ~any(stats.serving.date == s.year*1e4+s.month*1e2+s.day)
        stats.serving.days = stats.serving.days + 1;
    end
    stats.serving.date(end+1) = s.year*1e4+s.month*1e2+s.day;
    stats.serving.avg_cups_a_day = length(stats.serving.date)/stats.serving.days;
    stats.serving.hour(s.hour-work_start+1) = stats.serving.hour(s.hour-work_start+1) + 1;
    deltaT = floor((datenum(time_served)-datenum(Coffee.previousrequest.time))*24*60);
    stats.serving.waited(end+1) = deltaT;
    stats.fetcher{end+1} = Fetcher;
end

%% Store the Stat variable
jsonstats = mat2json(stats);
fid = fopen('CoffeeStats.json','w');
fprintf(fid,jsonstats);
fclose(fid);


        

Contact us