Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions SODM.m
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@
Data = runNthBlock(Data, blockIdx);
end

% Display "Currently evaluating a [description] trial" (see preBlock.m)
% disp('Currently Evaluating Random Trials')

% Evaluate Lottery for randomly chosen trial
SODM_pickTrials(Data)

% Close window
unloadPTB(monConfig, medConfig);
end
33 changes: 33 additions & 0 deletions lib/helpers/getOneBlockPerCondition.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
% Want a function which, given an input argument of the block number,
% returns the condition of that block (medical or monetary) and the block's

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, just noticed this — this does not describe the function at all. (Or rather, it describes lines 23 and 24 of the function.)

% beneficiary (self or other).


function [ uniqueIdx ] = getOneBlockPerCondition(blocks)

% adding paths?
addpath(genpath('./lib'));
addpath(genpath('./tasks/SODM'));

% blocks and numBlocks
numBlocks = length(blocks);

payoffKinds = cell.empty;
beneficiaries = cell.empty;

% iterate through the blocks
for blockIdx = 1:numBlocks
subsetofblocs = blocks{blockIdx};
conditions = subsetofblocs.conditions;

payoffKinds{blockIdx} = conditions.payoffKind;
beneficiaries{blockIdx} = conditions.beneficiary;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way to generalize that for tasks with different kinds of conditions would be to a) poll fieldnames in block.conditions and make them into table headers, b) populate the table with the condition assignments extracted from each block. This is perfect for a vectorized approach -- in fact, cellfun(@(block) struct2table(block.conditions), blocks) would be a one-line expression of that logic (haven't checked).

end

% make it into a table
blockTable = table(payoffKinds', beneficiaries');

% grab the unique indices to uniqueIdx
[~, uniqueIdx, ~] = unique(blockTable);

end
8 changes: 4 additions & 4 deletions lib/phase/pickAndEvaluateTrial.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function [ outcomeKind, outcomeLevel ] = pickAndEvaluateTrial(DataObject, config)
function [ outcomeKind, outcomeLevel ] = pickAndEvaluateTrial(block, config)
% Picks a recorded trial at random, evaluates it, and displays the outcome.
%
% This can be run as a post-block callback. To do this, include
Expand All @@ -8,8 +8,8 @@
% FIXME: This was written in a hurry, and should at some point be refactored.

%% 1. Pick an available trial at random
blockIdx = randi(DataObject.numFinishedBlocks);
block = DataObject.blocks{blockIdx};
% blockIdx = randi(block.numFinishedBlocks);
% block = block.blocks{blockIdx};
trialIdx = randi(height(block.data));
trial = block.data(trialIdx, :);
trial.refSide = 1; % Fix the display
Expand All @@ -27,7 +27,7 @@
end

%% 2. Evaluate the trial
% summary = experimentSummary(DataObject, blockIdx, trialIdx);
% summary = experimentSummary(block, blockIdx, trialIdx);
[ outcomeKind, outcomeLevel, outcomeColorIdx, trueProb, randDraw ] = evaluateTrial(trial);

%% 3. Draw the trial
Expand Down
120 changes: 120 additions & 0 deletions lib/phase/showTrialEvaluation.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
function [outcomeKind, outcomeLevel] = showTrialEvaluation(trial, config)
% Allow users to call this function from wherever they want
% Be able to receive the trial specification, block configuration.

% Evaluate the trial: adapted lines 92-end of pickAndEvaluateTrial.
%% 2. Evaluate the trial
% summary = experimentSummary(block, blockIdx, trialIdx);
[ outcomeKind, outcomeLevel, outcomeColorIdx, trueProb, randDraw ] = evaluateTrial(trial);

%% 3. Draw the trial
% 0. Open PTB window if it isn't yet opened (`isempty(Screen('Windows'))`)
standalone = false;
if isempty(Screen('Windows'))
standalone = true;
config = loadPTB(config);
config.runSetup.textures = loadTexturesFromConfig(config);
end


% 1. Use drawLotto and drawRef to show the lotto
config.task.fnHandles.bgrDrawFn(config, trial);
drawLotto(trial, config);
config.task.fnHandles.referenceDrawFn(config, trial);
Screen(config.device.windowPtr, 'Flip');
% 2. Disappear the non-picked choice
WaitSecs(5);
switch trial.choseLottery
case 0
config.task.fnHandles.referenceDrawFn(config, trial);
msg = 'You chose the certain option.';

case 1
windowPtr = config.device.windowPtr;
% Determine message to display

% For monetary gamble
if strcmp(config.runSetup.blockName, "Monetary") == 1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not work on Matlab versions prior to 2016b be — don't ask me why, but Matlab was very strict that strings are denoted by apostrophes, not by quotes.

Also, note that this code doesn't create a basecase for a block whose name is neither monetary nor medical, which means that it will fail hard in those cases.

lookupTbl = config.runSetup.lookups.txt;
message = textLookup(outcomeLevel, lookupTbl, windowPtr);
msg = 'You chose the gamble. Random draw got you ';
msg = [msg message];
end

% For medical gamble
if strcmp(config.runSetup.blockName, "Medical") == 1
lookupTbl = config.runSetup.lookups.txt;
message = textLookup(outcomeLevel, lookupTbl, windowPtr);
msg = 'You chose the experimental treatment. The final result was ';
msg = [msg message];
end

% (3. Re-paint lottery with true probability layout

if trial.ambigs > 0
trial.ambigs = 0;
trial.probs = trueProb;
end
drawLotto(trial, config);
% 4. Draw a line through the chosen random number
% 5. Highlight the winning amount)
otherwise
msg = 'No choice made in this trial.';
end
Screen(config.device.windowPtr, 'Flip');

% 6. Display the final outcome
WaitSecs(1);
if trial.choseLottery == 0
config.task.fnHandles.referenceDrawFn(config, trial);
elseif trial.choseLottery == 1
drawLotto(trial, config);
end
txtDims = getTextDims(config.device.windowPtr, msg);
xDim = config.device.screenDims(3)/2 - txtDims(1)/2;
yDim = config.device.screenDims(4) - 100; %moved text up from bottom of screen
DrawFormattedText(config.device.windowPtr, msg, xDim, yDim, [200 200 200]);
Screen(config.device.windowPtr, 'Flip');
disp(randDraw);

% 7. Wait for keypress
waitForKey(config.device.breakKeys, 5);

% 8. If this was a one-off show, close screen
if standalone
unloadPTB(config);
end
end

function [ outcomeKind, outcomeLevel, outcomeColorIdx, trueLotteryProb, randomDraw ] = evaluateTrial(trial)
% EvaluateTrial Given a trial row, evaluates it.
if trial.choseLottery == 0
outcomeKind = 'Reference';
outcomeLevel = trial.reference;
trueLotteryProb = NaN;
randomDraw = NaN;
outcomeColorIdx = [];
else
% Conduct lottery
ambig = trial.ambigs;
if ambig > 0
minProb = (1 - ambig) / 2;
trueLotteryProb = round(minProb + ambig * rand, 2);
else
trueLotteryProb = trial.probs;
end

randomDraw = rand;
if randomDraw <= trueLotteryProb
outcomeKind = 'Win';
outcomeLevel = trial.stakes;
outcomeColorIdx = trial.colors;
else
outcomeKind = 'Loss';
outcomeLevel = trial.stakes_loss;
outcomeColorIdx = 2 - (trial.colors - 1); % FIXME: Ugly hack, assumes only two colors indexed 1 and 2
end
randomDraw = round(randomDraw, 2);
end
end

35 changes: 35 additions & 0 deletions tasks/SODM/SODM_pickTrials.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
function [trial, config] = SODM_pickTrials(data)

% ugly hack?
config = data.blocks{end}.config;

% Show that trials have ended and lottery evaluations are about to begin
msg = 'Trials have ended. Please wait for the experimenter.';

windowPtr = config.device.windowPtr;
txtDims = getTextDims(config.device.windowPtr, msg);
xDim = config.device.screenDims(3)/2 - txtDims(1)/2;
yDim = config.device.screenDims(4) - 20;

DrawFormattedText(config.device.windowPtr, msg, xDim, yDim, [200 200 200]);
Screen('flip', windowPtr);

waitForKey(config.device.breakKeys); %experimenter presses 5 to continue

% go thru indices, pick trial and config
for index_block = getOneBlockPerCondition(data.blocks)'
block = data.blocks{index_block};
trialIdx = randi(height(block.data));
trial = block.data(trialIdx, :);
trial.refSide = 1;

config = block.config;

% want to evaluate showLotteryEvaluation for each of the four trials
showTrialEvaluation(trial, config)

% After receiving prompt, begin (next) lottery:
waitForKey(config.device.breakKeys);

end