# Generate randomly positioned rectangles with no overlap

Hello PsychoPy Discourse community!

I am trying to create a fully functioning Corsi Block Tapping task. The goal is to have 9 randomly placed, yet not overlapping rectangles appear on the screen. I can manage the random part, but often rectangles overlap.
My idea is to check, whether rectangles overlap, and if they do, to keep on generating new positions until no rectangles overlap, and only if no overlap is detected to actually draw the rectangles.

Here is the code I belive to be relevant:

``````    # store blocks as a dictionary (to switch between name/object)
blocks = {}
blocks['blk1']=blk1
blocks['blk2']=blk2
blocks['blk3']=blk3
blocks['blk4']=blk4
blocks['blk5']=blk5
blocks['blk6']=blk6
blocks['blk7']=blk7
blocks['blk8']=blk8
blocks['blk9']=blk9

# give blocks a new set of random locations
for label, block in blocks.items():
block.pos = random(2)*0.8-0.4
if block.overlaps(block):  # check for overlapping
block.pos = random(2)*0.8-0.4
else:
block.color = 'white'
``````

Any suggestions would be much appreciated!

@dvbridges, all versions on Pavlovia have the fault of overlapping rectangles. I currently am adapting a version I found on Pavlovia, trying to add some code to prevent the overlappingâ€¦ but with no success so far

The way Iâ€™ve dealt with this in the past is by using what I call a jittered grid.

Instead of giving the blocks free reign, create an array of locations on a grid and shuffle it. The following code will produce an array of 6 non-overlapping locations from a grid of 24. The amount of jitter can be changed to ensure there is no overlap.

``````#Variables for user to edit
rows = 4
columns = 6
nchoices = 6

bottom_left = [-.8,-.6]
top_right = [.8,.6]

scale = 0.15
jitter = .1

#Computed variables
nspots = rows * columns
spot_chosen = [0] * nspots

locations=[]
nselected = 0
iselected = []

for Idx in range(rows):
for Jdx in range(columns):
dotx = Jdx * (top_right[0]-bottom_left[0])/(columns-1) + bottom_left[0] + random.uniform(-jitter, jitter)
doty = Idx * (top_right[1]-bottom_left[1])/(rows-1) + bottom_left[1] + random.uniform(-jitter, jitter)
locations.append([dotx,doty])

random.shuffle(locations)
selected = []
for Jdx in range(nchoices+1):
dotx = Jdx * (top_right[0]-bottom_left[0]+jitter*2)/(nchoices) + bottom_left[0]-jitter
selected.append([dotx,-.9])

``````

As you can see, this hasnâ€™t been written for online, but replacing random should be fairly easy.

Best wishes,

Wakefield

Iâ€™m also interested in doing this. Did you end up finding a solution for this?

I found the following, which worked well. Unfortunately, it doesnâ€™t translate properly to javascript, so I wasnâ€™t able to run it online.

``````# initial state
blkIndex_3 = 0
nextSwitch_3 = blockDuration
doingResponse_3 = False
currBlock_3 = None
import scipy
import numpy
blockCoords_3 = []
dist_min_3 = 0
actualSequenceLength = min(sequenceLength_3,9)

# store answer blocks as a dictionary (to switch between name/object)
blocks_3 = {}
blocks_3['blk1_3']=blk1_3
blocks_3['blk2_3']=blk2_3
blocks_3['blk3_3']=blk3_3
blocks_3['blk4_3']=blk4_3
blocks_3['blk5_3']=blk5_3
blocks_3['blk6_3']=blk6_3
blocks_3['blk7_3']=blk7_3
blocks_3['blk8_3']=blk8_3
blocks_3['blk9_3']=blk9_3

# give blocks a new set of random locations
while True:
for label, block in blocks_3.items():
block.pos = random(2)*0.8-0.4
blockCoords_3.append(block.pos)
dist_3 = scipy.spatial.distance.pdist(blockCoords_3)
block.color = 'white'
if numpy.min(dist_3)>.11:
dist_min_3 = numpy.min(dist_3)
break
else:
blockCoords_3 = []
dist_3 = []
dist_min_3 = 0
``````

It is not very fancy, but it works. I dont know whether it translates well to JS. I defined fixed postions on the screen for every block, and then calculated a random jitter. Then added it to each postion manually, and randomized the postions in the list, to make it look like block were preseneted in a radom order. The rest of the task is as on Pavlovia.
In the â€”Prepare to start Routine â€śtrialâ€ťâ€” part of the code I added the following:
Note that I have 9 blocks.

``````blocks = {}
blocks['blk1']=blk1
blocks['blk2']=blk2
blocks['blk3']=blk3
blocks['blk4']=blk4
blocks['blk5']=blk5
blocks['blk6']=blk6
blocks['blk7']=blk7
blocks['blk8']=blk8
blocks['blk9']=blk9
``````

locations on the screen

``````locations = [(-.52, 0.3), (-.52, 0.03), (-.52, -0.25), (0.04, 0.3), (0.04, 0.03),(0.04,-.25), (0.47, 0.3), (0.47, 0.03), (0.47, -0.25)]
``````

create jitter

``````jitter = [np.random.uniform(-0.1, 0.1) for x in range(18)]
``````

``````locations_1 = [
[locations[0][0] + jitter[0],
locations[0][1] + jitter[1]],
[locations[1][0] + jitter[2],
locations[1][1] + jitter[3]],
[locations[2][0] + jitter[4],
locations[2][1] + jitter[5]],
[locations[3][0] + jitter[6],
locations[3][1] + jitter[7]],
[locations[4][0] + jitter[8],
locations[4][1] + jitter[9]],
[locations[5][0] + jitter[10],
locations[5][1] + jitter[11]],
[locations[6][0] + jitter[12],
locations[6][1] + jitter[13]],
[locations[7][0] + jitter[14],
locations[7][1] + jitter[15]],
[locations[8][0] + jitter[16],
locations[8][1] + jitter[17]]]
``````

Shuffle locations in list

``````np.random.shuffle(locations_1)
``````

set counter to 0

``````i = 0
#give blocks a new set of random locations
for label, block in blocks.items():
block.pos = locations_1[i]
i = i + 1 #add to counter to itterate through list
block.color = 'white'
``````

Also you probably need to add some libraries to the skript. These are the ones I used for the corsi task. some were there by default, others I added but not sure which. I believe to remember that the â€śnumpy.randomâ€ť was missing and the â€śnumpy as npâ€ť to call on the numpy lib.

``````from psychopy import locale_setup
from psychopy import prefs
from psychopy import sound, gui, visual, core, data, event, logging, clock
from psychopy.constants import (NOT_STARTED, STARTED, PLAYING, PAUSED,
STOPPED, FINISHED, PRESSED, RELEASED, FOREVER)

import numpy as np  # whole numpy lib is available, prepend 'np.'
from numpy import (sin, cos, tan, log, log10, pi, average,