Быстрый поиск разницы файлов

Ну собственно это история одной маленькой победы, которые происходят обычно у ИТишников каждый день 😉

Предыстория: при работе скрипта по заливке данных в БД из файла произошло зависание сервера. Скрипт работал в несколько потоков с одним файлом. Потому определить на каком именно месте файла произошла остановка не представлялось возможным. Удалять уже залитое в БД и стартовать скрипт заново — не вариант, скрипт и так работал двое суток, и терять их снова — ну так себе решение.

Решение №1. «В лоб». Ну думаю доработаю скрипт так, что если данные уже есть, то просто пропускаем. Т.е. перед вставкой выполняем проверку функцией вида:

function lsYet($period,$ls){
    global $db;
  $res=false;
  $sql="select posting_addresses.id from posting_addresses
    inner join ls on ls.id=posting_addresses.ls
    where 
    posting_addresses.period='$period' and ls.ls='$ls'";
    $query = $db->connection->prepare($sql);
    $query->execute();
    while ($row99 = $query->fetch()) {
      $res=true;
    };        
 return $res;
}

И без проблем дозальем то, чего нет в БД. Да не тут то было, оказывается операция select в этом случае весьма дорогостоящая, и т.к. в БД записей порядка 600тыс, и индексы проставлены на ls и period корректно, но всёж скорость проверки крайне низкая, и т.о. скорость «дозалития» сокращается с двух суток до суток. Ну что собственно не устраивает.

Решение №2. Вдумчивое. Решил было выгрузить ключевые строки (лицевой счет) в файлы: файл ls_in_base.txt — лицевые счета которые уже в БД и ls_all.txt — файл со всеми лицевыми счетами, которые должны быть в БД, отсортировав их командой sort:

sort ls_in_base.txt > ls_in_base.txt
sort ls_all.txt > ls_all.txt

Далее воспользуемся Linux командой comm, вычленив уникальные записи файла ls_all которые не содержаться в файле ls_in_base:

comm -23 ls_all.txt ls_in_base.txt > no_in_base.txt

И далее уже в скрипте вместо проверки наличия лс в БД при помощи запроса, проверяем наличие лс в БД при помощи in_array:

$no_in_base_ls=file_get_contents("no_in_base.txt");
$no_in_base_arr=explode("\n",$no_in_base_ls);
...
if (in_array($ls, $no_in_base_arr)==true){
...
заливаем данные в БД
...
}

В результате скорость увеличилась в разы, и БД дозалить удалось в течении часа

Чтиво за последнее время

Взрослое

Релокант 1-5, В момент начала ядерной войны в мир пришла система и перенесла всех жителей во вновь сгенерированный мир куда попали в т.ч. жители других миров которые разрушили свои миры. В целом за исключением некоторых нудных моментов. Оценка 3+/5

Звездный лорд 1-5. В принципе просто перечитка уже прочитанного ранее несколько лет назад. Ну возникла пауза, когда не мог ничего новенького найти ). Оценка 4 из 5

Автократия Гоблинов 1-3. Михаил Усачев. В принципе старая серия, начинал её читать еще несколько лет назад, но тогда не зашла. Сейчас зашла. Оценка 4/5

Кинетик 1-3. Анин А.О. Очередная книга про попаданца в прошлое. В принципе читабельно. Оценка 3 из 5

Хроники Апокалипсиса 1-5. Родион Дубина. Мир пал, на его месте возникли зомби. Главный герой крут и скоро станет еще круче. В принципе интересно. Оценка 4 из 5

Мастер Порталов 1-3. После того как чела сбил автобус, он становится магом и научился открывать порталы в другие миры. Оценка 4 из 5.

Детское

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

Внучка бабы Яги. Екатерина Козина. Внучка проводит каникулы у бабушки, которая оказывается не просто бабушка. 5/5

Yandex Map: отображение меток в зависимости от масштаба карты

Работал давече с плагином HeatMap для яндекс карт. Всё хорошо, но один нюанс — невозможно навесить эвент на клик по точке карты. Ну или не нашел как. Пришлось задействовать «финт ушами» — при достижении определенного приближения, принудительно отрисовывать поверх точек heatmap свои «кликабельные» точки. В результете родилось нечто подобное:

obj = data.result; 
                heatmap = new ymaps.Heatmap(obj, {
                    // Радиус влияния.
                    radius: 15,
                    // Нужно ли уменьшать пиксельный размер точек при уменьшении зума. False - не нужно.
                    dissipating: false,
                    // Прозрачность тепловой карты.
                    opacity: 0.8,
                    // Прозрачность у медианной по весу точки.
                    intensityOfMidpoint: 0.05,
                    // JSON описание градиента.
                    gradient: {
                           0.1: 'rgba(128, 255, 0, 0.7)',
                           0.2: 'rgba(255, 255, 0, 0.8)',
                           0.7: 'rgba(234, 72, 58, 0.9)',
                           0.9: 'rgba(162, 36, 25, 1)',
                           1.0: 'rgba(0, 0, 0, 1)'
                       }
                });
                heatmap.options.events.add('click', function (e) {   
                    console.log(e);
                    var objectId = e.get('objectId');    
                    //objectManager.objects.balloon.open(objectId);
                });                    
                heatmap.setMap(myMap); 

        
       
        
                myMap.events.add('boundschange', function () {
                    size = myMap.getZoom();
                    console.log(size);
                    if (size>15){
                        console.log("-- пора бы и нарисовать метки");
                        if (all_deleted==true){
                            console.log("--- рисуем метки");
                            // настройки кластеризакции
                            objectManager = new ymaps.ObjectManager({
                                clusterDisableClickZoom: true,
                                geoObjectOpenBalloonOnClick: true,
                                clusterize: false
                            }); //кластеризуем
                            objectManager=SetClusterProp(objectManager);     
                            myMap.geoObjects.add(objectManager);   
                            objectManager.add(obj);  
                            objectManager.objects.events.add('click', function (e) {   
                                console.log(e);
                                var objectId = e.get('objectId');    
                                objectManager.objects.balloon.open(objectId);
                            });                                        
                          all_deleted=false;  
                        };
                    } else {
                        if (all_deleted==false){
                            myMap.geoObjects.remove(myMap.geoObjects.get(myMap.geoObjects.getLength()-1));                          
                            all_deleted=true;  
                        };
                    };
                });
                

PixiJS: игра «жизнь» продолжение

В ходе наблюдения за жителями, заметил, что не очень хорошо смотрится рождение нового жителя, а именно он «рождается» в случайном месте карты. Не порядок. Пусть он рождается рядом с «мамой». Для этого изменим код генерации «нового жителя», чтобы можно было за ранее передавать координаты рождения жителя:

function GenerateNewCitizen(x,y){
   resident=new People(randomIntFromInterval(0,1),1,randomIntFromInterval(1,100),professions.get(1));   
   graphics = new PIXI.Graphics();           
   graphics.beginFill(professions.get(1).color);
   graphics.lineStyle(2, professions.get(1).color, 1);
   graphics.beginFill(professions.get(1).color, 1);           
   graphics.drawCircle(0,0, 1);  
   graphics.position.set(x, y);         
   graphics.direction=randomIntFromInterval(0,360);
   graphics.endFill();        
   graphics.resident=resident;
   residents.push(graphics);
   app.stage.addChild(residents[residents.length-1]);     
}

И соотвественно «рождение» жителя:

       // проверим, есть ли совпадение точек?
       // если возраст от 18..50
       // если полы противоположные
       // то считаем что это "лябовь" и размножаемся
        for (let j = 0; j < residents.length; j++) {   
            if (Math.round(residents[i].position.y)==Math.round(residents[j].position.y) && 
                    Math.round(residents[i].position.x)==Math.round(residents[j].position.x) && i!=j){
                      if (residents[i].resident.age>=18 && residents[i].resident.age<=50){
                        if (residents[j].resident.age>=18 && residents[j].resident.age<=50){
                            if (residents[j].resident.gender==0 && residents[i].resident.gender==1){
                                console.log("-это лябофь!");  
                                x=residents[j].position.x+1;
                                y=residents[j].position.y+1;
                                GenerateNewCitizen(x,y);
                            }
                        }                          
                      }               
            };
        };

И картинка стала выглядеть уже интереснее: жители стали «кучковаться», что логично — в тех местах где жителей больше они и рождаться стали чаще

Второй момент. Нужно как-то выделить возраст жителей. Может быть сделать более «старших» чуть толще?

        if (residents[i].resident.age>0 && residents[i].resident.age<18){
         residents[i].scale._x=1;   
         residents[i].scale._y=1;   
        };
        if (residents[i].resident.age>18 && residents[i].resident.age<50){
         residents[i].scale._x=1.5;   
         residents[i].scale._y=1.5;   
        };        
        if (residents[i].resident.age>50){
         residents[i].scale._x=1.8;   
         residents[i].scale._y=1.8;   
        }; 

Еще нашел ошибку, оказывается не все жители умирали по достижении 120 лет. Поправил:

        // прибавляем всем жителям по году жизни..
        for (let i = 0; i < residents.length; i++) {         
            residents[i].resident.age++;
            if (residents[i].resident.age>120){
                residents.pop(residents[i]); // в 120 лет жизненный путь завершается..
            };
            
        };

После этого жители стали стремительно вымирать после примерно 30-50 прошедших «лет» и на «планете» остались одни трупы:

Гнетущее впечатление, планета заваленная трупами.. Всё таки сделаю чтоб они убирались при смерти, пришлось серьёзно переписать логику, избавившись от «теневого» массива

       // перебираю каждого человека и двигаем его
    for (let i = 0; i < app.stage.children.length; i++) {
        if (app.stage.children[i].resident!==undefined){
            // регулируем размер жителей
            if (app.stage.children[i].resident.age>0 && app.stage.children[i].resident.age<18){
             app.stage.children[i].scale._x=1;   
             app.stage.children[i].scale._y=1;   
            };
            if (app.stage.children[i].resident.age>18 && app.stage.children[i].resident.age<50){
             app.stage.children[i].scale._x=1.5;   
             app.stage.children[i].scale._y=1.5;   
            };        
            if (app.stage.children[i].resident.age>50){
             app.stage.children[i].scale._x=1.8;   
             app.stage.children[i].scale._y=1.8;   
            };                
           //двигаем жителя (кудато идёт) 
            step=false;
            while (step==false){
                pre_y=app.stage.children[i].position.y+Math.sin(app.stage.children[i].direction);
                pre_x=app.stage.children[i].position.x+Math.cos(app.stage.children[i].direction);
                if ((pre_x>=0)&& (pre_x<=screen_width) && (pre_y>=0) && (pre_y<=screen_height)) {
                        step=true;
                } else {
                   app.stage.children[i].direction=randomIntFromInterval(0,360); 
                };

            };
           app.stage.children[i].position.y=app.stage.children[i].position.y+Math.sin(app.stage.children[i].direction);
           app.stage.children[i].position.x=app.stage.children[i].position.x+Math.cos(app.stage.children[i].direction);
            // размножаемся
            // проверим, есть ли совпадение точек?
            // если возраст от 18..50
            // если полы противоположные
            // то считаем что это "лябовь" и размножаемся
             for (let j = 0; j < app.stage.children.length; j++) {
                 if (app.stage.children[j].resident!==undefined){
                    if (Math.round(app.stage.children[i].position.y)==Math.round(app.stage.children[j].position.y) && 
                            Math.round(app.stage.children[i].position.x)==Math.round(app.stage.children[j].position.x) && i!=j){
                              if (app.stage.children[i].resident.age>=18 && app.stage.children[i].resident.age<=50){
                                if (app.stage.children[j].resident.age>=18 && app.stage.children[j].resident.age<=50){
                                    if (app.stage.children[j].resident.gender==0 && app.stage.children[i].resident.gender==1){
                                        console.log("-это лябофь!");  
                                        x=app.stage.children[j].position.x+1;
                                        y=app.stage.children[j].position.y+1;
                                        GenerateNewCitizen(x,y);
                                    }
                                }                          
                              }               
                    };
                     
                 }
             };           
        };

    }

Осталось придумать что-то, что бы позволило не вымирать населению? Может быть повысить «рождаемость»? Пусть иногда рождаются двойни-тройни?

                                        console.log("-это лябофь!");  
                                        for (let z = 0; z < randomIntFromInterval(0,3); z++) {
                                            x=app.stage.children[j].position.x+1;
                                            y=app.stage.children[j].position.y+1;
                                            GenerateNewCitizen(x,y);                                            
                                        };

Не помогло. Нужно разрешить рожать от 16 лет до 55. Плюс не нравится мне, что умирают жители строго по дистежении 120 лет. А если сделать что умирать будут чем больше лет начиная от 70, тем чаще?

        // прибавляем всем жителям по году жизни..
        for (let i = 0; i < app.stage.children.length; i++) {         
            if (app.stage.children[i].resident!==undefined){
                app.stage.children[i].resident.age++;
                if (app.stage.children[i].resident.age>60){
                    if (randomIntFromInterval(121,app.stage.children[i].resident.age)==120){
                        console.log("- умер "+i+" по достижению "+app.stage.children[i].resident.age+" лет");
                        app.stage.removeChild(app.stage.children[i]);                        
                    };
                };
            }            
        };

Уже выглядит красивее, но всё равно жители вымирают..

Нужно попробовать сделать так, чтобы рожали чаще. Если ранее дети рождались, если жители оказались в одной и той же точке, то теперь сделаем, что дети будут рождаться, даже если родители оказались просто рядом..

function DiffuzeCompare(x,y,x1,y1){
    res=false;
     if (Math.abs(x-x1)<=2&&Math.abs(y-y1)<=2){
         res=true;
     }
    return res;
};

                    if (DiffuzeCompare(app.stage.children[i].position.x,app.stage.children[i].position.y,app.stage.children[j].position.x,app.stage.children[j].position.y)==true) {
                              if (app.stage.children[i].resident.age>=16 && app.stage.children[i].resident.age<=55){
                                if (app.stage.children[j].resident.age>=16 && app.stage.children[j].resident.age<=55){
                                    if (app.stage.children[j].resident.gender==0 && app.stage.children[i].resident.gender==1){
                                        console.log("-это лябофь!");  
                                        for (let z = 0; z < randomIntFromInterval(0,3); z++) {
                                            x=app.stage.children[j].position.x+1;
                                            y=app.stage.children[j].position.y+1;
                                            GenerateNewCitizen(x,y);                                            
                                        };
                                    }
                                }                          
                              }                        
                    };

Вот теперь население стабильно стало расти. Теперь сделаем так, чтоб дети рождались только в роддоме:

                                               if (buldings[bb].bulding_type.name=="Роддом"){
                                                     x=randomIntFromInterval(buldings[bb].xx,buldings[bb].xx+buldings[bb].ww);
                                                     y=randomIntFromInterval(buldings[bb].yy,buldings[bb].yy+buldings[bb].hh);
                                                    GenerateNewCitizen(x,y);                                                                                        
                                               }
                                            }  

В итоге получили:

Pixi.js: игра «жизнь»

Продолжаю на досуге изучать 2D движек для работы с графикой на javascript. Решил написать игру «жизнь» со следующими правилами:

У каждого жителя есть возраст,пол и профессия.

  • Жители двигаются по всему полю хаотично
  • При достижении возраста 120 лет житель умирает
  • Если два жителя сталкиваются между собой и они разного пола от 18 до 50 лет, тогда они рожают ребенка

Сначала определим объекты карты:

// Люди
class People {
    /**
     * Конструктор
     * @param {type} gender - пол
     * @param {type} age - возраст
     * @param {type} health - здоровье
     * @param {type} profession - профессия из map professions
     * @returns {People}
     */
  constructor(gender,age,health,profession) {
      this.gender=gender;           // пол 0/1 м/ж
      this.age=age;                 // возраст
      this.health=health;           // здоровье
      this.profession=profession;   // профессия      
  }  
}
class Citizen {
    constructor(name,pers,color) {
      this.name=name;
      this.pers=pers; // изначальныый процент от общего колиества
      this.color=color;
    }
    
}
// Зданиям
class Building {
    /**
     * Конструктор
     * @param {type} name   название
     * @param {type} cnt    количество зданий на 1000 жителей
     * @returns {Building}
     */
    constructor(name,color,cnt) {
      this.name=name;
      this.color=color;
      this.cnt=cnt;
    }
    /**
     * Установить начальные координаты
     * @param {type} x
     * @param {type} y
     * @param {type} height
     * @param {type} width
     * @returns {undefined}
     */
    setSpawn(x,y,height,width){
      this.x=x;  
      this.y=y;
      this.height=height;
      this.width=width;        
    }
}

Зададим переменные для игры:


/**
 * Профессии, они же модели поведения
 * @type Map
 */
professions=new Map(
        [
            // индекс, название,  % от всего населения
            [1,new Citizen("Детсадовец",10,0xFFFF0B)],    // ночует дома, днём ходит в детский сад
            [2,new Citizen("Школьник",10,0xAA0000)],      // ночует дома, днем до 13:00 в школе, потом идёт домой через магазин
            [3,new Citizen("Студент",10,0xFFFFFF)],       // ночует дома, днем до 17:00 в институте, потом идёт домой через магазин
            [4,new Citizen("Продавец",20,0xFF0000)],      // ночует дома, днём в магазине, потом идёт домой через магазин
            [5,new Citizen("Офисный клерк",20,0xFF3300)], // ночует дома, днём в офисе, потом идёт домой через магазин
            [6,new Citizen("Рабочий",20,0x0000FF)],       // ночует дома, днём на заводе, потом идёт домой через магазин
            [7,new Citizen("Пенсионер",10,0xDE3249)]      // ночует дома, днём шляется по магазинам или по улицам
        ]
);
buldings_types=new Map(
        [   
            [1,new Building("Жилище",0xDE3249,10)], // индекс, название, количество на 1000 жителей
            [2,new Building("Школа",0xAA0000,1)],
            [3,new Building("Университет",0xFFFFFF,1)],
            [4,new Building("Магазин",0xFF0000,2)],
            [5,new Building("Офис",0xFF3300,3)],
            [6,new Building("Завод",0x0000FF,1)],                
            [7,new Building("Детсад",0xFFFF0B,1)]                
        ]
);


// ну пусть размеры пока в экран, потом можно поиграться
var scrollWidth=GetScrollWidth();
var screen_width = window.innerWidth-4; //получаем ширину экрана
var screen_height = window.innerHeight-4; // получаем высоту экрана

residents_count=1000;   // начальное количество жителей
residents=[];           // массив жителей
buldings=[];            // массив зданий
cur_seconds=0;          // текущая секунда
cur_minuts=0;           // текущая минута
cur_hour=0;             // текущая час
cur_day=0;              // текущая день
cur_month=0;            // текущая месяц
cur_year=0;             // текущая год

max_FPS=60;

Напишем процедуры генерации зданий и жителей:

function GenerateNewCitizen(){
   x=randomIntFromInterval(1,screen_width-width);
   y=randomIntFromInterval(1,screen_height-height);      
   resident=new People(randomIntFromInterval(0,1),1,randomIntFromInterval(1,100),professions.get(1));
   
   graphics = new PIXI.Graphics();           
   graphics.beginFill(professions.get(1).color);
   graphics.lineStyle(2, professions.get(1).color, 1);
   graphics.beginFill(professions.get(1).color, 1);           
   graphics.drawCircle(0,0, 1);  
   graphics.position.set(x, y);         
   graphics.direction=randomIntFromInterval(0,360);
   graphics.endFill();        
   graphics.resident=resident;
   residents.push(graphics);

   app.stage.addChild(residents[residents.length-1]); 
    
}

/**
 * Начальная генерация зданий
 * @returns {undefined}
 */
function InitGenerateBuilding(){
  for (let i=1;i<= buldings_types.size;i++){
      cnt=buldings_types.get(i).cnt/1000*residents_count;
      yet_cnt=1;
      while (yet_cnt<=cnt){
        // случайным образом генерируем координаты и размеры здания
        width=randomIntFromInterval(20,60);
        height=randomIntFromInterval(20,60);
        x=randomIntFromInterval(1,screen_width-width);
        y=randomIntFromInterval(1,screen_height-height);      
        // если наложений нет, то добавляю здание в массив
        if (CheckingOverlaysRect(x,y,width,height,buldings)==false){
                console.log("Добавляю "+buldings_types.get(i).name+" №"+yet_cnt);
                graphics = new PIXI.Graphics();  
                graphics.lineStyle(2, buldings_types.get(i).color, 1);
                graphics.drawRect(x, y, width, height);
                buldings.push(graphics); 
            app.stage.addChild(buldings[buldings.length-1]);            
                FPSText = new PIXI.Text(buldings_types.get(i).name,new PIXI.TextStyle({fontFamily: 'Arial',fontSize: 11,}));
                FPSText.x = x;
                FPSText.y = y;            
            app.stage.addChild(FPSText);         
            yet_cnt++;
        };
      }
  };  
}

/**
 * Проверка наложения квадратов друг на друга
 * @param {type} x
 * @param {type} y
 * @param {type} width
 * @param {type} height
 * @param {type} rects
 * @returns {res|Boolean}
 */
function CheckingOverlaysRect(x,y,width,height,rects){
  res=false;
    for (let bi=1;bi<= rects.length;bi++){
         rect_height=rects[bi-1].getBounds().height;
         rect_width=rects[bi-1].getBounds().width;
         rect_x=rects[bi-1].getBounds().x;
         rect_y=rects[bi-1].getBounds().y;
         //console.log(rect_height,rect_width,rect_x,rect_y);
         if ((x>=rect_x)&(x<=rect_x+rect_width)){res=true;};
         if ((y>=rect_y)&(y<=rect_y+rect_height)){res=true;};
         if ((x+width>=rect_x)&(x+width<=rect_x+rect_width)){res=true;};
         if ((y+height>=rect_y)&(y+height<=rect_y+rect_height)){res=true;};         
    };  
  return res;
}

/**
 * Начальная генерация жителей
 * @returns {undefined}
 */
function InitGeneratePeoples(){
        
    for (let i=1;i<= professions.size;i++){ //перебираем все профессии
        console.log("-генерирую "+professions.get(i).name);
        for (let cnt=1;cnt<= professions.get(i).pers*residents_count/100;cnt++){
          x=randomIntFromInterval(1,screen_width-width);
          y=randomIntFromInterval(1,screen_height-height);      
          resident=new People(randomIntFromInterval(0,1),randomIntFromInterval(1,100),randomIntFromInterval(1,100),professions.get(i));


           graphics = new PIXI.Graphics();           
           graphics.beginFill(professions.get(i).color);
           graphics.lineStyle(2, professions.get(i).color, 1);
           graphics.beginFill(professions.get(i).color, 1);           
           graphics.drawCircle(0,0, 1);  
           graphics.position.set(x, y);         
           graphics.direction=randomIntFromInterval(0,360);
           graphics.endFill();        
           graphics.resident=resident;
           residents.push(graphics);

        app.stage.addChild(residents[residents.length-1]); 
          
          
          
        }
    }    
}

Создадим сцену и запустим время:

const app = new PIXI.Application({ 
    width:screen_width,
    height:screen_height,
    background: '#1099bb' ,
    antialias: true
});
document.body.appendChild(app.view);

app.stage.hitArea = app.screen;

InitGenerateBuilding(); // генерируем здания
InitGeneratePeoples();  // генерируем жителей

let ticker = PIXI.Ticker.shared;   
ticker.autoStart = false;
ticker.maxFPS=max_FPS;
ticker.start();

const style = new PIXI.TextStyle({
    fontSize: 20 
});
FPSText = new PIXI.Text('',style);
FPSText.x = 10;
FPSText.y = 10;   
app.stage.addChild(FPSText);         
StatText = new PIXI.Text(residents.length,style);
StatText.x = 10;
StatText.y = 30;   
app.stage.addChild(StatText);         


// пусть жители оживут!
ticker.add(function (time) {     
    cur_seconds++;
    if (cur_seconds==61){
        cur_seconds=0;cur_minuts++;
        // прибавляем всем жителям по году жизни..
        for (let i = 0; i < residents.length; i++) {         
            residents[i].resident.age++;
            if (residents[i].resident.age==120){
                residents.pop(residents[i]); // в 120 лет жизненный путь завершается..
            };
            
        };
    };
    if (cur_minuts==61){cur_minuts=0;cur_hour++;};
    if (cur_hour==25){cur_hour=0;cur_day++;};    
    if (cur_day==366){cur_day=0;cur_year++;};       
    FPSText.text="С начала эпохи прошел: "+cur_minuts+" год"; // выводим FPS
    StatText.text="Жителей:"+residents.length;
    // перебираю каждого человека и двигаем его
    for (let i = 0; i < residents.length; i++) {         
        step=false;
        while (step==false){
            pre_y=residents[i].position.y+Math.sin(residents[i].direction);
            pre_x=residents[i].position.x+Math.cos(residents[i].direction);
            if ((pre_x>=0)&& (pre_x<=screen_width) && (pre_y>=0) && (pre_y<=screen_height)) {
                    step=true;
            } else {
               residents[i].direction=randomIntFromInterval(0,360); 
            };
            
        };
       residents[i].position.y=residents[i].position.y+Math.sin(residents[i].direction);
       residents[i].position.x=residents[i].position.x+Math.cos(residents[i].direction);
       // проверим, есть ли совпадение точек?
       // если возраст от 18..50
       // если полы противоположные
       // то считаем что это "лябовь" и размножаемся
        for (let j = 0; j < residents.length; j++) {   
            if (Math.round(residents[i].position.y)==Math.round(residents[j].position.y) && 
                    Math.round(residents[i].position.x)==Math.round(residents[j].position.x) && i!=j){
                      if (residents[i].resident.age>=18 && residents[i].resident.age<=50){
                        if (residents[j].resident.age>=18 && residents[j].resident.age<=50){
                            if (residents[j].resident.gender==0 && residents[i].resident.gender==1){
                                console.log("-это лябофь!");  
                                GenerateNewCitizen();
                            }
                        }                          
                      }               
            };
        };
    }
});
1 42 43 44 45 46 308