Эксперимент по созданию психотипов с обратной связью и несколькими циклами if

Я пытаюсь использовать представление Coder, чтобы провести эксперимент, включающий обратную связь и несколько условных операторов. Как вы это делаете? Задача в конечном итоге будет включать 4 математических задачи, и участникам будет разрешено иметь до 3 попыток для каждой задачи. Структура должна быть примерно такой...

Цикл 1: проходит через 4 задачи

Цикл 2: позволяет до 3 попыток на задачу

Цикл 3: если ответ правильный, скажите «правильно» и переходите к следующей задаче; в противном случае скажите «неправильно» и спросите, хотят ли они попробовать еще раз или двигаться дальше.

Я впервые использую Python, и я не могу разобраться с перегибами в коде. Сообщение об ошибке не возвращается, код не регистрирует ответ, и поэтому задача останавливается на месте на экране подсказки. Код ниже. Я не включал библиотеки и другие настройки.

t=0
nProblem=4
nAttempt=3

while currentProb <= nProblem:
    problemTimer.reset()
    attempt = 1

    # *prompt* updates
    prompt.setAutoDraw(True)
    prompt.setText(u'Problem prompt will go here.\n\nType in your answer and press enter to submit.', log=False)

    while attempt <= nAttempt:

        response = []
        # *response* updates
        core.wait(1) #LB - using this in place of that enormous if-statement

        event.clearEvents(eventType='keyboard')
        theseKeys = event.getKeys(keyList=['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'])
        # check for quit:
        if "escape" in theseKeys:
            endExpNow = True
        if ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0') in theseKeys: # subject responds with number value
            response.append(theseKeys) # will tack on responses to previous responses

        while event.getKeys(keyList=['return'])==[]:

            # *timer* updates
            if t <= 0.0:
                # keep track of start time/frame for later
                timer.setAutoDraw(True)
            #elif timer.status == STARTED and t >= (0.0 + (600-win.monitorFramePeriod*0.75)): #most of one frame period left
                #timer.setAutoDraw(False)
            #if timer.status == STARTED:  # only update if being drawn
                timer.setText(str(round((600+routineTimer.getTime())/60,1)) , log=False)

            # *minutesleft* updates
            if t >= 0.0:
                # keep track of start time/frame for later
                minutesleft.setAutoDraw(True)
            #elif minutesleft.status == STARTED and t >= (0.0 + (600-win.monitorFramePeriod*0.75)): #most of one frame period left
            #minutesleft.setAutoDraw(False)

            numberlist=event.getKeys(keyList=['1','2','3','4','5','6','7','8','9','0','backspace','return'])
            for number in numberlist:
                #if key isn't backspace, add key pressed to the string
                if number !='backspace':
                    response.append(number)
                #otherwise, take the last letter off the string
                elif len(text)>=0:
                    response.remove(numberlist[number-1])
            #continually redraw text onscreen until return pressed
            answer = visual.TextStim(win, text=response,color="black",pos=(0,-100))
            answer.draw()
            win.flip()
            event.clearEvents()

        if len(theseKeys) > 0:  # at least one key was pressed
            response.keys.extend(theseKeys)  # storing all keys
            response.rt.append(response.clock.getTime())

        #check for quit
        if "escape" in theseKeys:
            endExpNow = True

        if response == '9999': # was this correct?
            correctAns = 1
        else: 
            correctAns = 0
        if theseKeys == 'enter':
            response.keys.extend(theseKeys) # storing all keys
            response.rt.append(attemptresponse.clock.getTime())
            if correctAns == 1:
                attempt += 888 #ends and goes to next problem
                currentProb += 1
                dataFile.write(attempt,attemptresponse,theseKeys,response,correctAns) #output separated by commas
                #dataFile.write('PID    COND    PROB    ATT TIME    RESP\n')
                response_correct.draw()
                win.flip()
                event.waitKeys()
            if correctAns == 0:
                attempt += 1 #LB = was previously setting to 1 forever
                dataFile.write(attempt-1,attemptresponse,theseKeys,response,correctAns) #output separated by commas
                response_incorrect.draw()
                win.flip()
                theseKeys = event.getKeys(keyList=['q','space'])
                if theseKeys == 'q':
                    continueRoutine = False
                if theseKeys == 'space':
                    prompt.draw()
                    win.flip()
                    event.waitKeys()

person Jennifer    schedule 10.09.2014    source источник
comment
Привет, Дженнифер, это хороший вопрос, и Джонас сделал несколько очень полезных предложений (пожалуйста, не забудьте отметить его ответ как правильный, если он решит вашу проблему). Но в будущем для таких вопросов логики программирования было бы лучше сделать пример кода намного более кратким: убрать все строки, касающиеся сохранения данных, времени и стимулов, которые не связаны с фактическим вопросом. Вы обнаружите, что больше людей захотят прочитать код, если им будет легче увидеть его структуру, к чему относится ваш вопрос.   -  person Michael MacAskill    schedule 11.09.2014


Ответы (1)


Я не могу написать ваш полный код, но, надеюсь, укажу на несколько вещей, которые помогут вам в большей части пути.

Получение ответов

theseKeys = event.getKeys(keyList=['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'])
if "escape" in theseKeys:

Здесь theseKeys может содержать только то, что находится в keyList, поэтому "побег" никогда не существует. Расширьте keyList с помощью «escape» - и, возможно, «enter», который вы используете позже.

if ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0') in theseKeys:

theseKeys — это список, и когда вы делаете «(x, y, z) в списке», он будет искать элемент (x, y, z), а не какие-либо вхождения x, y и z. Если у вас есть список ключей, как указано выше, вы ЗНАЕТЕ, что любой ответ без экранирования является одним из них, поэтому он не нужен. Ну действуй

theseKeys = event.getKeys(keyList=['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'escape'])
if "escape" in theseKeys:
    core.quit()  # assuming that psychopy.core is imported
elif "enter" in theseKeys:
    # Something something
else:
   response.append(theseKeys[0])  # OBS: pick the first response

Петли

Похоже, вы хотите использовать цикл for, а не цикл while. Используя циклы for, вам не нужно отслеживать номер текущего цикла. Так что вместо

while currentProb <= nProblem:

do

for currentProb in range(nProblem):

Затем приращение currentProb происходит автоматически, и цикл завершается, когда это необходимо. Это намного элегантнее, когда это возможно.

Ожидание ответов

Я немного сомневаюсь, захотите ли вы использовать event.waitKeys(), а не event.getKeys() в цикле while, и использовать аргумент maxWait, если вы хотите контролировать время ожидания, и использовать core.Clock(), если вы хотите отслеживать время. Цикл while подходит, если вы хотите что-то анимировать, но если нет, то event.waitKeys() будет намного проще и безопаснее.

И, наконец, пока вы пытаетесь заставить это работать, используйте множество операторов print для проверки фактического содержимого theseKeys и других переменных. Это лучший способ отладки и выявления ошибок.

person Jonas Lindeløv    schedule 10.09.2014