NeuroTask Card Sorting Test Demo Experiment Run Experiment

NeuroTask Card Sorting Test

Jaap Murre

This is the NeuroTask Scripting implementation of the well-known Wisconsin Card Sorting Test with slightly different shapes and colors. Cards can be dragged onto one of the four target cards.


Only 64 cards are shown in this version. No data is stored. A brief score is presented at the end (categories [or runs] completed, total correct, and number of perseveration errors).

This is a fairly complex script of about 200 lines. These lines, however, includes everything the task needs, including on-the-spot generation of the cards (using the built-in icons). 

This test also works on tablets and smart phones with touch, as well as with mouse on desktops.

If you are a registered user and signed in, you can here copy this script and its stimuli to your own account, where you can edit it and change it in any way you want.

It is absolutely free to register (no credit card info asked!). You can then instantly copy this experiment with one click and edit it, change its accompanying texts, its landing page, stimuli, etc. Invite your colleagues, friends, or students to check out your experiment. There is no limit on how many people can do your experiment, even with a free account.

The catch? There is no catch! Just keep in mind that with a free account, you cannot collect data. For teaching that is usually not a problem. For research, prepaid data collection (unlimited subjects) starts as low as €10.00 for a 10-day period.

main.setfontsize(60);

function preamble()
{
    main.setfontsize(65);
    
    instruction("You will see four cards placed at the top and a card at the bottom to match to one of them."
              + "<br><br>There is a secret  rule for matching the cards and you will need to guess what it is.");
    instruction("Your task is to take the card at the bottom and drag it on top of one of the " 
              + "four cards you think matches it according to the secret rule.");
    instruction("You can drag the card at the bottom by clicking on it with the left mouse button "
              + "and dragging it while keeping the button pressed.");
    instruction("On a tablet, smart phone, or other touch screen, you can drag the lower card around with your finger.");          
    instruction('You will get feedback on each choice: either "Correct" or "Incorrect".');
    instruction('After you drop a card on one of the four cards on top, a new one will appear at the bottom.');
    instruction('You continue guessing like this for the rest of the cards.<br><br>'
              + 'Take as long as you like for each decision, but bear in mind that you cannot change your mind after a card has been placed.'
              + '<br><br>Try to get as many right as possible.');
    instruction('From time to time the rule will change <strong>without telling you this</strong>.<br><br>You will then need to discover the new rule.');

//    main.style("font-size","1em");
}

function createCard(left,top)
{
    left = left || "center";
    top = top || 57;
    
    return addblock(left,top,18,25,"white")
            .style("border","thin grey solid")
            .style("background-color","#fafafa")
            .style("border-radius","0.5em");
}

function setCard(c,color,shape,number,left,top)
{
    left = left || "center";
    top = top || 57;
    
    var sp = '<span style="display:inline-block;margin-left:0.8em"> </span>', 
        br = "<br>", 
        s, t;

    switch (shape)
    {
        case 'star': s = '<i class="icon-star"></i>'; break;
        case 'circle': s = '<i class="icon-circle"></i>'; break;
        case 'square': s = '<i class="icon-stop"></i>'; break;
        case 'triangle': s = '<i class="icon-play icon-rotate-270"></i>'; break;
        case 'cross': s = '<i class="icon-plus"></i>'; break;
    }

    switch (number)
    {
        case 1: t = s; break;
        case 2: t = s + br + br + s; break;
        case 3: t = s + sp + br + sp + s + br + s + sp; break;
        case 4: t = s + br + s + sp + s + br + s; break;
    }
    
    c.text(t,100)
     .style("color",color);
    c.moveto(left,top);
    
    return c;
}

function makeCard(color,shape,number,left,top,fixed)
{
    var c = createCard(left,top);
    
    if (!fixed)
    {
        c.moveable();
    }

    return setCard(c,color,shape,number,left,top);
}

function getDeck()
{
    var colors = ['red','green','blue','gold'],     // yellow seems too light, so use gold instead
        shapes = ['circle','star','square','cross'],
        numbers = [1,2,3,4],
        deck = [],
        c, s, n;
        
    for (c = 0; c < colors.length; c++)
    {
        for (s = 0; s < shapes.length; s++)
        {
            for (n = 0; n < numbers.length; n++)
            {
                deck.push({
                    color: colors[c],
                    shape: shapes[s],
                    number: numbers[n]
                });
            }
        }
    }
    
    deck = shuffle(deck);
    return deck;
}

function getRules()
{
    return [].concat(shuffle(['color','shape','number']),
                     shuffle(['color','shape','number']));
}

preamble(); // Show instructions

var feedback = addblock("center","center",100,10)
                  .text("Drag the card below on top of the correct one above"),

    //score_block = addblock("right","bottom",30,10),
                  
    r = [   { color: "red",   shape: "circle", number: 1, x:  5 },
            { color: "green", shape: "star",   number: 2, x: 28 },
            { color: "blue",  shape: "square", number: 3, x: 53 },
            { color: "gold",  shape: "cross",  number: 4, x: 77 }  ],
            
    cards = [], d,
    c, deck = getDeck(),
    rules = getRules(), 
    rule = 0,
    total_correct = 0,
    correct_run = 0,
    perseverations = 0,
    h, i, e, pile;

for (h = 0; h < r.length; h++)
{
    cards.push(makeCard(r[h].color,r[h].shape,r[h].number,r[h].x,5,true));
}

d = makeCard("yellow","triangle",4); // Will be modified immediately

var breakouter = false; // Labelled statements not implemented yet

for (c = 0; c < deck.length; )
{
    setCard(d,deck[c].color,deck[c].shape,deck[c].number);
    d.style('opacity',1);
    
//    d.await('mouseup');

    while (true) {
        
        RAF();
        
        pile = -1;
        for (i = 0; i < cards.length; i++)
        {
            if (d.overlap(cards[i]) > 0.65)
            {
                pile = i;
                await(250);
                break;
            }
        }
        
        if (pile > -1)
        {
            if (deck[c][rules[rule]] == r[pile][rules[rule]])
            {
                feedback.text("<b>Correct</b>",150);
                ++total_correct;
                ++correct_run;
                
                if (correct_run === 10)  // i.e., if 10 in run
                {
                    ++rule;             // Start a new rule
                    correct_run = 0;    // Start new run
                }
                
                if (rule === rules.length)
                {
                    breakouter = true;
                    break; // Early break in case of very fast subject
                }
            }
            else
            {
                feedback.text("<b>Incorrect</b>",150);
                correct_run = 0;
                
                if (rule > 0 && deck[c][rules[rule-1]] == r[pile][rules[rule-1]])
                {
                    ++perseverations; // Subject used previous rule
                }
            }
    
            c++;                            // Only advance on correct drop
            d.animate('opacity',1,0,1000);  // Fade out card
            await(1000);
            feedback.clear();
            await(250);
            
    /*        score_block.text("Cat: " + rule     // Show during development only
                             + ", Per: " + perseverations
                             + ", Cor: " + total_correct 
                             + ", Run: " + correct_run
                             ,60).style("color","grey"); */                        

            break; // Break out of while
        }
        
        if (breakouter) {
            break;
        }
    }
}

feedback.text("Thank you for participating!");
await(2000);
feedback.text("You had #{total_correct} matches correct out of 64. "
            + "You completed #{rule} rule runs and had #{perseverations} perseverations"
            + "<br><br>Press any key to leave the test.");
await('keypress');

You can download the files as follows: Click on the file (link) and then right-click and choose Save as... from the menu. Some media files (e.g., sound) will have a download button for this purpose.

This experiment has no files of this type
This experiment has no files of this type
This experiment has no files of this type
This experiment has no YouTube links
This experiment has no files of this type