69 lines
3.2 KiB
JavaScript
69 lines
3.2 KiB
JavaScript
|
|
// casegen/citizens.js — генерація мешканців району
|
|||
|
|
const N = require('./names');
|
|||
|
|
const { allUnits, allJobs } = require('./district');
|
|||
|
|
const { pick, chance, shuffle, ri } = require('./rng');
|
|||
|
|
|
|||
|
|
const BLOOD = ['O(I) Rh+', 'O(I) Rh+', 'A(II) Rh+', 'A(II) Rh+', 'B(III) Rh+', 'AB(IV) Rh+', 'O(I) Rh−', 'A(II) Rh−'];
|
|||
|
|
const PRINTS = ['дуга', 'петля', 'петля', 'завиток', 'завиток'];
|
|||
|
|
|
|||
|
|
function makeCitizens(r, district) {
|
|||
|
|
const citizens = [];
|
|||
|
|
const usedNames = new Set(), usedPhones = new Set(), usedDna = new Set();
|
|||
|
|
let nextId = 1;
|
|||
|
|
|
|||
|
|
function person(sex, last, ageRange) {
|
|||
|
|
let first, full;
|
|||
|
|
do { first = pick(r, sex === 'ч' ? N.MALE : N.FEMALE); full = `${first} ${last}`; } while (usedNames.has(full));
|
|||
|
|
usedNames.add(full);
|
|||
|
|
const age = ri(r, ageRange[0], ageRange[1]);
|
|||
|
|
const height = sex === 'ч' ? ri(r, 165, 195) : ri(r, 152, 183);
|
|||
|
|
let phone;
|
|||
|
|
do { phone = `+380${pick(r, ['50', '63', '66', '67', '68', '73', '95', '96', '97', '98', '99'])}${String(ri(r, 0, 9999999)).padStart(7, '0')}`; } while (usedPhones.has(phone));
|
|||
|
|
usedPhones.add(phone);
|
|||
|
|
let dna;
|
|||
|
|
do { dna = Array.from({ length: 8 }, () => ri(r, 0, 15)); } while (usedDna.has(dna.join(',')));
|
|||
|
|
usedDna.add(dna.join(','));
|
|||
|
|
return {
|
|||
|
|
id: 'c' + nextId++, name: full, first, last, sex, age, birthYear: 2026 - age,
|
|||
|
|
blood: pick(r, BLOOD), height,
|
|||
|
|
shoe: Math.max(35, Math.min(46, Math.round(height * 0.24) + ri(r, -1, 1))),
|
|||
|
|
printType: pick(r, PRINTS), printSeed: ri(r, 1, 2 ** 30), coat: pick(r, N.COATS),
|
|||
|
|
smoker: chance(r, 0.3), dog: chance(r, 0.2) ? pick(r, N.DOG_NAMES) : null,
|
|||
|
|
tattoo: chance(r, 0.25) ? pick(r, N.TATTOOS) : null,
|
|||
|
|
phone, dna, home: null, job: null, workplace: null, spouse: null
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const unitList = allUnits(district);
|
|||
|
|
const sizes = {};
|
|||
|
|
shuffle(r, unitList.filter(u => u[0] !== 'C')).forEach((u, i) => sizes[u] = i < 3 ? 1 : pick(r, [1, 2, 2, 3, 3, 4]));
|
|||
|
|
for (const u of unitList) if (u[0] === 'C') sizes[u] = pick(r, [1, 1, 2]);
|
|||
|
|
for (const unit of unitList) {
|
|||
|
|
const dorm = unit[0] === 'C';
|
|||
|
|
const size = sizes[unit];
|
|||
|
|
const last = pick(r, N.SURNAMES);
|
|||
|
|
if (size === 1) {
|
|||
|
|
const p = person(pick(r, ['ч', 'ж']), last, dorm ? [19, 45] : [25, 74]);
|
|||
|
|
p.home = unit; citizens.push(p);
|
|||
|
|
} else {
|
|||
|
|
const a = person('ч', last, [26, 68]);
|
|||
|
|
const b = person('ж', chance(r, 0.7) ? last : pick(r, N.SURNAMES), [Math.max(22, a.age - 8), Math.min(70, a.age + 8)]);
|
|||
|
|
if (!dorm) { a.spouse = b.id; b.spouse = a.id; }
|
|||
|
|
a.home = b.home = unit; citizens.push(a, b);
|
|||
|
|
for (let k = 2; k < size; k++) {
|
|||
|
|
const kid = person(pick(r, ['ч', 'ж']), last, [18, Math.max(19, a.age - 22)]);
|
|||
|
|
kid.home = unit; citizens.push(kid);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const jobs = shuffle(r, allJobs(district));
|
|||
|
|
const workers = shuffle(r, citizens.filter(c => c.age <= 65));
|
|||
|
|
workers.slice(0, jobs.length).forEach((c, i) => { c.job = jobs[i].title; c.workplace = jobs[i].building; });
|
|||
|
|
for (const c of citizens) if (!c.job)
|
|||
|
|
c.job = c.age > 62 ? 'пенсіонер' : c.age < 23 ? 'студент' : 'тимчасово не працює';
|
|||
|
|
return citizens;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = { makeCitizens };
|