[From Bruce Abbott (950307.1500 EST)]

Bill Powers (950306.1210 MST)

Below is another version of the discriminative stimulus experiment, built
on Bruce Abbott's program SDTEST1. This is SDTEST2p. The final letter
indicates it is Powers' version, in case someone else is working on an

In the middle of the cursor a number is shown, indicating the absolute
average error between the cursor position and whichever target is red. The
object is to keep the number as small as possible.

Maybe it's just me, but I found it almost impossible to keep my eye on that
number attached to the cursor. It might work better to use a point-score
instead which increases at some rate when the participant is keeping the
cursor within some range of the current target, and providing an auditory
beep for each point.

I've created a somewhat different task using this strategy. The participant
sees two targets on the screen and a single cursor. Points can be earned by
keeping the cursor aligned with the currently active target, as indicated by
the cursor color (If acquisition of the discriminated operant is to be
tested, the participant would not be told how to earn points or what the
relationship between cursor color and active target is.) Points are awarded
AT RANDOM while the cursor is being kept within point-range of the active

The task is analogous to a two-key discrimination task in which pecks to the
left key are rewarded on a variable ratio schedule when the keys are green
and on the right key (same schedule) when the keys are red.

Data are recorded to an ASCII file for subsequent analysis by the program of
your choice.




program SDtest3;

{ Program to investigate the role of the discriminative stimulus. The
  participant's task is earn points by keeping a cursor (green or red
  vertical line) aligned between one of two sets of white vertical lines
  (targets), accomplished by moving the mouse left and right. When the
  cursor is green, the LEFT target is the active target. When the cursor
  is red, the RIGHT target is the active target. The cursor color changes
  at random times throughout the procedure. Data (disturbance, mouse,
  and active target values each 1/60 second) are written in three columns
  to an ASCII text file called SDDATA.XXX, where XXX is a unique 3-digit

  Written by Bruce Abbott
                     Psychological Sciences
             Indiana University - Purdue University
                    Fort Wayne, IN 46805-1499
                         (219) 481-6399

  CRT, DOS, Graph, GrUtils, Mouse;

  MAXDATA = 3600;

  datalist = array[1..MAXDATA] of integer;
  dataptr = ^datalist;

  h, d, state: dataptr;
  MaxX, MaxY, c, Oldc, CursColor, SD, score,
  T1L, T1R, T2L, T2R: integer;
  slow: real;
  ch: char;

procedure InitHeapVars;

procedure DisposeHeapVars;

procedure InitScreen;
  MaxX := GetMaxX; MaxY := GetMaxY;
  outtextXY(MaxX div 2 - 110, 20, 'DISCRIMINATED OPERANT STUDY');
  rectangle(20, 40, MaxX-20, 160);
  outtextXY(50, 60,
  'You can earn points by keeping the cursor aligned with one of the two');
  outtextXY(50, 80,
  'sets of white target marks. You move the cursor by using the mouse.');
  outtextXY(50, 100,
  'At any given moment, the correct target on which to align the cursor');
  outtextXY(50, 120,
  '(and thus earn points) may change. Try to earn as many points as');
  outtextXY(50, 140,
  'possible. To start the experimental run, press the SPACE BAR...');
  outtextXY(MaxX div 2 - 20, MaxY div 2 - 60, 'POINTS');
  T1L := MaxX div 3 - 5;
  T1R := MaxX div 3 + 5;
  T2L := 2*MaxX div 3 - 5;
  T2R := 2*MaxX div 3 + 5;

procedure DrawTarget;
  line(MaxX div 3, MaxY div 2 - 35, MaxX div 3, MaxY div 2 - 20);
  line(MaxX div 3, MaxY div 2 + 35, MaxX div 3, MaxY div 2 + 20);
  line(2*MaxX div 3, MaxY div 2 - 35, 2*MaxX div 3, MaxY div 2 - 20);
  line(2*MaxX div 3, MaxY div 2 + 35, 2*MaxX div 3, MaxY div 2 + 20);

procedure InitParams;
  Slow := 0.005;
  SD := 1;
  CursColor := LightGreen;

procedure InitDist(dist: dataptr);
  i: integer;
  d1, d2, d3, avg, max, tmp : real;
  d1 := 0.0; d2 := 0.0; d3 := 0.0;
  for i := 1 to MAXDATA do
      d1 := random * 10000.0 - 5000.0;
      d2 := d2 + slow*(d1 - d2);
      d3 := d3 + slow*(d2 - d3);
      dist^[i] := round(d3);
  avg := 0.0;
  for i := 1 to MAXDATA do avg := avg + d^[i];
  avg := avg/MAXDATA;
  for i := 1 to MAXDATA do d^[i] := d^[i] - round(avg);
  max := 0;
  for i := 1 to MAXDATA do if abs(d^[i]) > max then max := abs(d^[i]);
  for i := 1 to MAXDATA do { normalize to max of 120 }
    tmp := 120.0/max;
    d^[i] := round(d^[i]*tmp);

procedure DrawCursor(c, init: integer);
  if init = 0 then
    line(oldc, maxy div 2 - 20, oldc, maxy div 2 + 20);
  oldc := c + maxx div 2;
  line(oldc, maxy div 2 - 20, oldc, maxy div 2 + 20);

procedure Beep;

function Reward: boolean;
  if random < 0.025 then Reward := true else Reward := false;

procedure UpDateScore(var Score: integer);
var NumStr: string[3];
  Str(Score:3, NumStr);
  Bar(maxx div 2 - 16, maxy div 2 - 38,
      maxx div 2 + 8, maxy div 2 - 46);
  OuttextXY(maxx div 2 - 15, maxy div 2 - 45, numstr);

procedure Practice;
var handle, cursor: integer;
  handle := mousex;
  drawcursor(handle + d^[121], 1);
    handle := mousex;
    cursor := handle + d^[121];
    drawcursor(cursor, 0);
    if keypressed then ch := readkey;
  until ch = ' ';

procedure RunExpt;
var i, j, x, handle, cursor,
  count, switchcount: integer;
  setViewPort(0, 0, MaxX, 165, clipoff);
  SetViewPort(0, 0, MaxX, MaxY, clipoff);
  count := 0;
  score := 0;
  SD := 1;
  switchcount := random(480)+120;
  for j := -120 to MAXDATA-1 do { 2-sec run-in period }
      i := abs(j) + 1;
      handle := mousex;
      cursor := handle + d^[i];
      h^[i] := handle;
      state^[i] := SD;
      drawcursor(cursor, 0);
      x := cursor + MaxX div 2;
      Case SD of
        1: begin
             if (x > T1L) and (x < T1R)
               then if reward then UpdateScore(Score);
        2: begin
             if (x > T2L) and (x < T2R)
               then if reward then UpdateScore(Score);
      if (count >= switchcount) then
        count := 0;
        case SD of
          1: begin
               SD := 2;
               CursColor := LightRed;
          2: begin
               SD := 1;
               CursColor := LightGreen;
        DrawCursor(cursor, 0);

function FileExists(Filename: PathStr): Boolean;
  TextFile: Text;
  Assign(TextFile, Filename);
  FileExists := (IOResult = 0);

procedure SaveData;
  I, Num: Word;
  Result: Integer;
  DataFile: Text;
  Filename: String[12];
  ID: String[3];
  Stop: Boolean;
  Stop := False;
  Num := 0;
    Str(Num:3, ID);
    for i := 1 to 2 do
      if ID[i] = ' ' then ID[i] := '0';
    Filename := 'SDDATA.' + ID;
    if (FileExists(Filename)) then
        if Num = 999 then Stop := True else inc(Num);
    else Stop := True;
  until (Stop);
  Assign(DataFile, Filename); { assumes current drive/directory }
  Writeln('Writing data to disk as ', Filename, ' ....');
  if IOResult <> 0 then
    Writeln('ERROR: Unable to open data file.')
      for I := 1 to MAXDATA do
        writeln(DataFile, h^[i]:5, d^[i]:5, state^[i]:3);
      Writeln('Data successfully written to disk.');
        'Please record your data filename (indicated above), then press');
      Writeln(' the ESCape key to end this program...');

    ch := readkey;
  until ch = #27;