DashedSentence in a PennController trial

PennController for IBEX Forums FAQ / Tips DashedSentence in a PennController trial

This topic contains 3 replies, has 2 voices, and was last updated by Jeremy Jeremy 2 weeks, 1 day ago.

Viewing 4 posts - 1 through 4 (of 4 total)
  • Author
    Posts
  • #4220
    Jeremy
    Jeremy
    Keymaster

    EDIT: PennController 1.7 now includes Controller elements. This is still a new functionality, so use with caution.

    Example:

    newTrial(
      newText("instructions", "Click on the button below to start reading")
        .print()
      ,
      newButton("Start reading")
        .print()
        .wait()
        .remove()
      ,
      getText("instructions")
        .remove()
      ,
      newController("DashedSentence", {s: "The mouse that the cat is chasing runs fast"})
        .print()
        .log()
        .wait()
        .remove()
      ,
      newButton("I'm done")
        .print()
        .wait()
    )

    END OF EDIT

    I am working on a general solution to inject native-Ibex-format controllers inside PennController trials.

    In the meantime, this page gives you two options to present self-paced reading tasks along PennController trials.

    Option 1: use the native-Ibex DashedSentence controller

    Pros: you get all the features of the native controller
    Cons: you don’t get the features of PennController, ie. no .log command to store metadata from your table’s columns

    Example:

    // This line is required for PennController experiments
    PennController.ResetPrefix(null)
    
    // Sequence of randomly picked pairs of test + control trials
    PennController.Sequence( "practice" , rshuffle("test", "control") )
    
    // This is the standard way of defining items in Ibex
    var items = [
        ["practice", "DashedSentence", {s: "This is a practice item"}]
    ]
    
    // No need to use these if uploading CSV tables to Resources/chunks_includes
    PennController.AddTable( "testTable" , `Sentence
    Hello world
    Bye world
    "Yes, or, no"`) // Note the quotes when including commas
    
    PennController.AddTable( "controlTable" , `Equation,Result1,Result2,Result3
    7*7,49,53,32
    489+256,745,667,233
    81/9,9,7,8`)
    
    
    // Here we use Template to generate trials from testTable
    // Note that we use the Ibex-native DashedSentence controller
    PennController.Template( "testTable" ,
      row => ["test", "DashedSentence", {s: row.Sentence}]
    )
    
    
    // Here we use Template to generate trials from controlTable
    // Now we use a PennController trial
    PennController.Template( "controlTable" ,
      row => PennController( "control" ,
        newText("What is the result of "+row.Equation+"?")
            .print()
        ,
        newText("Negative feedback", "Are you sure?")
        ,
        // This is a dirty javascript trick to randomize the answers
        newScale("result", ...[row.Result1, row.Result2, row.Result3].sort(()=>0.5-Math.random()) )
            .settings.labelsPosition("right")
            .print()
            // We wait until the participant selects the right answer
            .wait(
                getScale("result").test.selected(row.Result1)
                    .failure( getText("Negative feedback").print() )
            )
      )
    )

    Option 2: code the task’s logic yourself

    Pros: you get all the features and flexibility of PennContrller
    Cons: you have to recode everything from scratch…

    Example reproducing the default behavior of DashedSentence (self-paced reading mode and dashed display)

    // This function generates an array of PennController commands
    // It's basically a sequence of text.settings.text() and key.wait()
    // The first parameter is the sentence to display (words should be separated by space characters)
    // The second (optional) parameter determines whether the sentence should be removed at the end
    //
    dashed = (sentence, remove) => {
      let words = sentence.split(' '),  blanks = words.map(w=>w.split('').map(c=>'_').join(''));
      let textName = 'dashed'+words.join('');
      // We'll return cmds: the first command consists in creating (and printing) a Text element with dashes
      let cmds = [ newText(textName, blanks.join(' ')).print() ];
      // We'll go through each word, and add two command blocks per word
      for (let i = 0; i < = words.length; i++)
        cmds = cmds.concat([ newKey('dashed'+i+words[i], " ").settings.log().wait() , // Wait for (and log) a press on Space
                             getText(textName).settings.text(blanks.map((w,n)=>(n==i?words[n]:w)).join(' ')) ]); // Show word
      if (remove)  // Remove the text after the last key.wait() is parameter specified
        cmds.push(getText(textName).remove());
      return cmds;
    }
    
    // Illustration
    //
    PennController(
      newText("instructions", "Click on the button below to start reading")
        .print()
      ,
      newButton("Start reading")
        .print()
        .wait()
        .remove()
      ,
      getText("instructions")
        .remove()
      ,
      // We call the function here
      // Note the ... before dashed because it returns an array, which we want to inject
      //
      ...dashed("The mouse that the cat is chasing runs fast", 'remove')
      ,
      newButton("I'm done")
        .print()
        .wait()
    )
    • This topic was modified 2 months ago by Jeremy Jeremy. Reason: Added an example using Ibex-native DashedSentence
    #4885
    Avatar
    daniela
    Participant

    Hi Jeremy,

    I’m having trouble implementing newController() inside a template. Here’s what I’ve got (I just added newController() and its commands to an already functioning script):

    PennController.Template( PennController.GetTable(“fictional.csv”),
    variable => [“critical”,
    newController(“DashedSentence”, {s: [variable.bio], display: “in place”,blankText: “…”})
    .print()
    .log()
    .wait()
    .remove()
    ,
    newController(“DashedSentence”, {s: [variable.pronoun,variable.verb,variable.adj,variable.objnp,variable.time,variable.spillover]})
    .print()
    .log()
    .wait()
    .remove()
    )

    I get the following error when I try to run it: Command ‘length’ unknown on Controller element ‘DashedSentence’. (PennController: 22). I’ve updated to PC 1.7, and have also tried to figure it out in the PC trial tester with no luck.

    Did I do something wrong, or does newController() not work inside a template (or both)?

    Best,
    Daniela

    • This reply was modified 2 weeks, 1 day ago by Avatar daniela.
    • This reply was modified 2 weeks, 1 day ago by Avatar daniela.
    #4888
    Avatar
    daniela
    Participant

    *Edit: I’m missing the closing ] bracket, but this was just a mistake in shortening it for the forum

    #4889
    Jeremy
    Jeremy
    Keymaster

    Hi Daniela,

    The Controller element, as such, is supposed to go inside a trial created with newTrial (previously PennController). In your script, you are trying to use it like a regular native-Ibex definition, which won’t work because your newController commands appear outside newTrial/PennController. If you want to use the old Ibex definition, just build on Option 1 in my first message. If you want to use the Controller element, build on the example I gave in my Edit instead.

    Also, I’m not sure what you’re trying to do with your arrays of variable. in the s parameter: what should happen to all those values?

Viewing 4 posts - 1 through 4 (of 4 total)

You must be logged in to reply to this topic.