Oh, I misunderstood slightly. I was thinking you would have trials_2 as you have it now, but trials would only loop across the dotprobetrial 24 times after the condition order is established in the blank trial. trials_3 would be redundant in my version, but your solution might work better in some ways. The reason that it’s the same order of stimuli on every cycle is that nTrials is only shuffled once, where you want it to be shuffled after every six trials, but honestly I’m not entirely sure how because your two-loop structure seems like it should avoid that problem.
However, now that I think about it, making the types random on every cycle will also introduce the risk of the end of one cycle sharing stimuli with the start of the next. As for that trial/row playing twice, I think I know why it’s happening but it’s hard to avoid when you are juggling two different types of randomization that aren’t well-connected to each other.
Thinking about it more, it’s going to take something fairly complex to satisfy all of your randomization requirements, to the point where it might even be easier to pre-construct a bunch of random orders in separate files and cycle through those files, rather than trying to procedurally randomize each time. That said, I think there is a way to do it. Here’s the basic outline of it:
- Make separate lists for each stimulus type, i.e., six different lists of four items each. You could either implement this by having six separate files, or you could do this manually after reading the files in.
- Cycle through those six lists, popping one thing from each into the final list, and then shuffle each set of six, making note of the first and last one in the shuffled order.
- If this is not the first set of six, compare the first one to the last one of the previous set of six, and if they are the same, reshuffle.
and you would need to do all of this for every block of 24 trials. This would pretty much all happen in the “begin routine” code for you blank trial, with the risk that the last trial from one set of 24 would be the same as the first trial from the next set of 24. The overall structure of the experiment would be trials_2 is your primary outer loop, repeating for however many blocks you want total, and “trials” only goes around dotprobetrial with 24 repetitions, after the blank trial code element has established the trial order for that block.
Here’s a rough concept of what the randomization would look like, but note that this is just to show you the kind of nested randomization you would need. This isn’t connected to the condition file, you’ll need to figure out how to implement it in the right way.
datStructure = [[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4]] # A list of six lists (one per type), each with four items (conditions).
blockOrder =  # This will hold a set of pairs in the format [type, condition].
for i in range (0,4):
# Ultimately we are cycling through these six things four times.
subOrder =  # This will hold the order for each set of six.
for j in range(0, len(datStructure)):
subOrder.append([j,datStructure[j].pop()]) # pulls one of the conditions at random w/out replacement
#subOrder now contains one instance of each type, with a randomly chosen condition for each, in random order.
if len(blockOrder) > 0:
while subOrder == blockOrder[-1]: # Just comparing the Type element of the start of this set of six and the end of the last set of six, to make sure the same type is not repeated.
shuffle(subOrder) # If it is repeated, re-randomize until it isn't.
for k in range(0, len(subOrder)): # Once that's all done, add these trials to the final trial list.
This is just doing it with lists of numbers rather than actual full conditions, but the output of this should be a list that has 24 ‘trials’ (in this case pairs in the form [type, condition]), each one unique (so no repeats of the same trial type with the same condition), and no consecutive types (because within each set of six they are all distinct, and it makes sure that the first element of the next set doesn’t match the last element of the last set).
This isn’t the exact code you should use because it doesn’t connect to the condition file, but it gives you an idea of the kind of structure for the randomization you’d want to do for each block of trials. You just need to figure out a way to line it up with the actual conditions and feed it to trialhandler.