Verifiquei seu código e realizei pequenas alterações...
Segue seu novo código:
//array carros
var xCarros = [0, 0, 0, 500, 500, 500];
var yCarros = [37, 93, 145, 205, 259, 313];
var velocidadeCarros = [2, 3.5, 4, 2, 3.5, 4];
function mostraCarros(){
for (var i = 0; i < carros.length; i++){
image (carros[i], xCarros[i], yCarros[i], 48, 48);
}
}
function movimentaCarros(){
for (var i = 0; i < (carros.length)/2; i++){
xCarros[i] += velocidadeCarros[i];
}
// se comparar com o código original, as chaves estavam após o segundo FOR e portanto o primeiro laço nunca terminaria
for (var i = (carros.length)/2; i < carros.length; i++){
xCarros[i] -= velocidadeCarros[i];
}
}
// mudei um pouco o retorno de seus carros. Do modo que estava tínhamos muitos IF que, obrigatoriamente, estariam dentro de laços.
// dessa forma reduzimos o código e verificamos todas as possibilidades.
function voltasCarros(){
for(let i = 0; i < (carros.length)/2; i ++){
if(passouTodaTela(xCarros[i])){
xCarros[i] = 0;
}
}
for(let i = (carros.length)/2; i < carros.length; i ++){
if(passouTodaTela2(xCarros[i])){
xCarros[i] = 500;
}
}
}
function passouTodaTela2(xCarro){
return xCarro < -50;
}
function passouTodaTela(xCarro){
return xCarro > 500;
}
// alterei seu contador para duas situações (carros indo e carros vindo) limitando sempre a metade dos carros.
// isso evita o conflito de posicionamento dos carros, pois em um laço mandamos ele ir e no outro voltar.