Restart trial

PennController for IBEX Forums Support Restart trial

This topic contains 4 replies, has 2 voices, and was last updated by Avatar ekakoki 1 month ago.

Viewing 5 posts - 1 through 5 (of 5 total)
  • Author
    Posts
  • #7069
    Avatar
    ekakoki
    Participant

    Hello,

    I’ve been trying to write a code for a series of practice trials that would each restart until the desired choice is selected. However, I keep running into the error “Cannot read property ‘id’ of undefined”. This is what I have so far:

    newVar("selected", "")
    
    const whichOne = (number, selectorName) => [
        getSelector(selectorName).test.selected(getImage("o" + number))
            .success(
                newAudio("o" + number + "selected", "o" + number + "Audio.m4a")
                    .play()
                    .wait()
                ,
                selected = number)
            .failure(whichOne(number + 1))
    ]
    
    const runPractice = (LP,RP,LO,RO,tag) => [
        clear()
        ,
        defaultImage.size(200,200)
        ,
        newCanvas("images", 1500, 600)
            .color("white")
            .add(  0 , 100 , newImage("p1", LP + ".jpeg" ).size(400, 400) )
            .add(450 , 100 , newImage("p2", LP + RP + ".jpeg").size(600,400) )
            .add(1100 , 100 , newImage("p3", RP + ".jpeg").size(400, 400) )
            .add(  0 , 500 , newImage("o1", LO + ".png") )
            .add(200 , 500 , newImage("o2", RO + ".png") )
            .add(550 , 500 , newImage("o3", LO + ".png") )
            .add(750 , 500 , newImage("o4", RO + ".png") )
            .add(1100 , 500 , newImage("o5", LO + ".png") )
            .add(1300, 500 , newImage("o6", RO + ".png") )
            
            .print("center at 50vw","top at 2em")
        ,
        newButton("Go").center().wait()
        ,
        newAudio("description", tag + ".m4a")
            .play()
            .wait()
        ,
        newSelector("response")
            .add( getImage("o1") , getImage("o2") , getImage("o3") , getImage("o4") , getImage("o5") , getImage("o6"))
            .wait()
        ,
        newButton("whichOneLaunch").callback(whichOne(1)).click()
    ]
    
    Template("examples.csv", row =>
        newTrial("practice",
            newButton("runPracticeLaunch")
                .callback(...runPractice(row.LP,row.RP,row.LO,row.RO,row.tag))
                .click()
            ,
            getVar("selected").test.is(row.correctChoice)
                .failure(newButton("Restart").callback(getButton("runPracticeLaunch").click()))
            ,
            newHtml("readyscreen", "readyscreen.html")
                .center()
                .print()
            ,
            newButton("Continue")
                .center()
                .print()
                .wait()
        )
    )

    I’m fairly new to using .callback() commands, so that could be the issue, but I’m not sure how else to format this. I would appreciate any suggestions to make this run! Thank you!

    • This topic was modified 1 month ago by Avatar ekakoki.
    #7071
    Jeremy
    Jeremy
    Keymaster

    Hello,

    There are a couple problematic aspects with your code. First, elements are specific to trials, so you cannot define a Var element outside the scope of a newTrial. Second, your whichOne function runs the risk of an infinite recursive loop (although I have to say it’s a pretty smart way of testing many values without having to duplicate your code). I recommend you read this guide to get a better idea of when commands are executed

    All callback commands will run a series of commands when the corresponding element’s relevant event happens (eg. a click on a Button element). They’re mainly useful to escape the purely top-down execution of the code, in allowing for interactions to unfold while the main thread of the script is waiting somewhere. It is true that they can also be used to re-execute a pre-defined block of code, but I think you are overusing the callback command in your code

    I think what you want is this:

    const whichOne = (numbers, selectorName) => numbers.map( number =>
        getSelector(selectorName).test.selected(getImage("o" + number))
            .success(
                newAudio("o" + number + "selected", "o" + number + "Audio.m4a")
                    .play()
                    .wait()
                ,
                getVar("selected").set(number)
            )
    )
    
    const runPractice = (LP,RP,LO,RO,tag,correctChoice) => [
        clear()
        ,
        newCanvas("images", 1500, 750)
            .color("white")
            .add(  0 , 100 , newImage("p1", LP + ".jpeg" ).size(400, 400) )
            .add(450 , 100 , newImage("p2", LP + RP + ".jpeg").size(600,400) )
            .add(1100 , 100 , newImage("p3", RP + ".jpeg").size(400, 400) )
            .add(  0 , 500 , newImage("o1", LO + ".png") )
            .add(200 , 500 , newImage("o2", RO + ".png") )
            .add(550 , 500 , newImage("o3", LO + ".png") )
            .add(750 , 500 , newImage("o4", RO + ".png") )
            .add(1100 , 500 , newImage("o5", LO + ".png") )
            .add(1300, 500 , newImage("o6", RO + ".png") )
            .add( "center at 50%", "bottom at 100%", newButton("Go") )
            .print("center at 50vw","top at 2em")
        ,
        getButton("Go").wait().remove()
        ,
        newAudio("description", tag + ".m4a")
            .play()
            .wait()
        ,
        newSelector("response")
            .add( getImage("o1") , getImage("o2") , getImage("o3") , getImage("o4") , getImage("o5") , getImage("o6") )
            .wait()
        ,
        ...whichOne([1,2,3,4,5,6],"response")
        ,
        getVar("selected").test.is(row.correctChoice)
            .success( 
                newHtml("readyscreen", "readyscreen.html")
                    .center()
                    .print()
                ,
                getButton("Continue").print("center at 50%","bottom at 100%",getCanvas("images"))
            )
            .failure( getButton("runPracticeLaunch").click() )
    ]
    
    Template("examples.csv", row =>
        newTrial("practice",
            newVar("selected", 0)
            ,
            defaultImage.size(200,200)
            ,
            newButton("runPracticeLaunch")
                .callback(...runPractice(row.LP,row.RP,row.LO,row.RO,row.tag,row.correctChoice))
                .click()
            ,
            newButton("Continue")
                .center()
                .wait()
        )
    )

    I couldn’t test this code with your project’s material (feel free to share the demonstration link with me so I can do it) but I tried an non-Template non-Audio version of it which worked. Note that I’m printing the button onto the Canvas element because otherwise they appear below it

    Jeremy

    #7072
    Avatar
    ekakoki
    Participant

    Thank you for the help! It runs!…But I also realized that I’d need to include the trial number in describing which audio to play, as each trial has a different correct answer. I tried simply adding the trial number as a new parameter and into the newAudio line of whichOne, but it came back with another undefined property error. I then tried taking the newAudio line out completely and using it immediately afterwards:

        ...whichOne([1,2,3,4,5,6], "response")
        ,
        newAudio("ex" + exNum + "o" + getVar("selected") + ".m4a").play().wait()
    

    However, it won’t play anything upon clicking on the options, and it doesn’t let me continue to the next practice example. The demonstration link is here: https://farm.pcibex.net/r/EIXHMT/
    Maybe I can’t use getVar in this context? But I’m not sure why not.

    #7073
    Jeremy
    Jeremy
    Keymaster

    You cannot use getVar that way, as explained in this guide I mentioned earlier

    Your first attempt was on the right track, but maybe you forgot to include the trial number in addition to the selection index?

    const whichOne = (numbers, selectorName, ex) => numbers.map( number =>
        getSelector(selectorName).test.selected(getImage("o" + number))
            .success(
                newAudio("o" + number + "selected", "ex" + ex + "o" + number + ".m4a")
                    .play()
                    .wait()
                ,
                getVar("selected").set(number)
            )
    )
    

    and then use it like this:

    ...whichOne([1,2,3,4,5,6], "response", exNum)
    

    Jeremy

    #7074
    Avatar
    ekakoki
    Participant

    That was it! Thank you so much for your help, everything is running smoothly now!

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

You must be logged in to reply to this topic.