🎥 EstudioVirtual — Rascunho de uma simulação de profissionais

São 00:54 enquanto escrevo isso no Obsidian. Tô tomando um Monster (Pacific Punch). Gostei bastante até.

Registro passado.

Projeto no Github

A ideia original era começar a modelar o CRUD de uma produção, mas acabei desanimando. Aí veio o estalo: e se eu começasse pelos profissionais que compõem uma produção? Ator, diretor, dublê... Afinal, são eles que dão vida ao projeto, junto com o produtor.

Então, rabisquei um primeiro esboço de um sistema de trabalhadores inspirando-me no TMDB (The Movie Database), com o objetivo de simular pessoas com diferentes características, funções, habilidades e personalidades.

Deixei tudo comentado para ajudar no entendimento!

Classe Crew

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Crew {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstName;
    private String lastName;

    // Sexo/Gênero (Masculino, Feminino e Não Binário)
    @Enumerated(EnumType.STRING)
    private GenderEnum gender;

    // Papel do profissional (ator, diretor, roteirista...)
    @Enumerated(EnumType.STRING)
    private CrewRoleEnum role;

    // Gênero cinematográfico de especialização (ação, drama, etc)
    @Enumerated(EnumType.STRING)
    private GenreEnum specialtie;

    // Traços de personalidade do indivíduo (ainda a ser detalhada)
    @ElementCollection
    @Enumerated(EnumType.STRING)
    private Set<PersonalityTraitEnum> personalityTraits = new HashSet<>();

    // Atributos de desempenho e características pessoais (ainda a ser detalhada)
    private Integer popularity;
    private Integer artisticCreativity;
    private Integer experience;
    private Integer productivity;
    private Integer stress;

    // Flags de status
    private Boolean isAdult;
    private Boolean isDead = false;
    private Boolean isOnVacation;
    private Boolean isAvailable;

    // Datas importantes
    private LocalDate birthDate;
    private LocalDate deathDate;
    private LocalDate vacationStartDate;
    private LocalDate vacationEndDate;

    // Salário base esperado
    private BigDecimal baseSalary;

    // Relação com contratos (ainda a ser detalhada)
    @OneToMany(mappedBy = "crew", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Contract> contracts = new HashSet<>();
}

Enum de Funções

Listei os principais papéis da indústria criativa. A ideia é que cada um tenha comportamento, salário e faixa etária própria

public enum CrewRoleEnum {
    ACTOR,
    DIRECTOR,
    SCREENWRITER,
    CINEMATOGRAPHER,
    EDITOR,
    COMPOSER,
    ART_DIRECTOR,
    COSTUME_DESIGNER,
    SOUND_DESIGNER,
    VISUAL_EFFECTS_SUPERVISOR,
    WRITER,
    VFX_ARTIST,
    MAKEUP_ARTIST,
    STUNT_PERFORMER
}

Enum de Personalidade

Ainda em construção, mas já temos alguns traços para influenciar decisões e interações futuras

public enum PersonalityTraitEnum {
    WORKAHOLIC,
    PRODIGIO,
    GASTADOR,
    CAPITALISTA
}

Geração Automática de Profissionais

Criei um serviço para gerar 50 profissionais aleatórios. A ideia aqui é testar como a combinação de idade, papel, personalidade e atributos impacta nos salários, além de servir para fazer testes de população (vou comentar mais pra frente)

public void generateRandomCrews() {
    List<Crew> crews = new ArrayList<>();
    Random random = new Random();

    for (int i = 0; i < 50; i++) {
        // Geração de atributos aleatórios
        Set<PersonalityTraitEnum> traits = generateRandomPersonalities();
        CrewRoleEnum role = CrewRoleEnum.values()[random.nextInt(CrewRoleEnum.values().length)];
        LocalDate birthDate = generateRandomBirthDate(role);
        GenderEnum gender = GenderEnum.values()[random.nextInt(GenderEnum.values().length)];
        GenreEnum specialty = GenreEnum.values()[random.nextInt(GenreEnum.values().length)];

        int age = Period.between(birthDate, LocalDate.now()).getYears();
        int experience = experienceService.calculateExperience(role, specialty, age);
        int popularity = random.nextInt(101);
        int artisticCreativity = random.nextInt(101);
        int productivity = random.nextInt(101);

        BigDecimal baseSalary = salaryService.calculateSalary(
            role, specialty, age, experience, popularity, artisticCreativity, productivity
        );

        // Construção do objeto Crew
        Crew crew = Crew.builder()
            .firstName(crewGenerateNameService.generateFirstName(random, gender.name()))
            .lastName(crewGenerateNameService.generateLastName(random))
            .gender(gender)
            .role(role)
            .specialtie(specialty)
            .personalityTraits(traits)
            .popularity(popularity)
            .artisticCreativity(artisticCreativity)
            .experience(experience)
            .productivity(productivity)
            .stress(random.nextInt(101))
            .isAdult(true)
            .isDead(false)
            .isOnVacation(random.nextDouble() < 0.1)
            .isAvailable(random.nextDouble() < 0.9)
            .birthDate(birthDate)
            .baseSalary(baseSalary)
            .build();

        // Se a pessoa estiver de férias, configura datas e disponibilidade
        if (Boolean.TRUE.equals(crew.getIsOnVacation())) {
            LocalDate today = LocalDate.now();
            crew.setVacationStartDate(today.minusDays(random.nextInt(7)));
            crew.setVacationEndDate(today.plusDays(random.nextInt(14) + 1));
            crew.setIsAvailable(false);
        }

        crews.add(crew);
    }

    // Salva todos os funcionários no banco
    crewRepository.saveAll(crews);
}

Idade + papel + gênero = XP

A experiência é baseada na idade, considerando um início típico de carreira por papel e com multiplicadores que variam pelo gênero cinematográfico (bem legal, mas longe de ser realista)

public int calculateExperience(CrewRoleEnum role, GenreEnum specialty, Integer age) {
    int baseMaxExperience = age - getMinimumEducationAge(role);
    if (baseMaxExperience <= 0) return 0;

    // Variação aleatória de experiência, multiplicadores de cargo e gênero
    double baseExperienceRatio = 0.5 + (Math.random() * 0.5);
    double roleMultiplier = getRoleExperienceMultiplier(role);
    double specialtyMultiplier = getSpecialtyExperienceMultiplier(specialty);

    double finalExperience = baseMaxExperience * baseExperienceRatio * roleMultiplier * specialtyMultiplier;
    return (int) Math.round(finalExperience);
}

Salário Baseado em "mérito", demanda e experiência (O mais complicado de gerar realismo)

Apenser de ser complicado, o cálculo do salário é meu trecho favorito — mistura lógica de mercado com métricas individuais é meio que brincar de Deus. Por favor, tente fazer um sistema assim!

public BigDecimal calculateSalary(...) {
    // Faixa de salário base por papel
    Map<CrewRoleEnum, double[]> roleSalaryRanges = getRoleSalaryRanges();

    double[] salaryRange = roleSalaryRanges.getOrDefault(role, new double[]{4000.0, 60000.0});

    // Calcula a experiência com base na idade
    double experienceFactor = getExperienceFactor(age, experience, role);
    
    // Base + mercado + performance
    double baseSalary = salaryRange[0] + ((salaryRange[1] - salaryRange[0]) * experienceFactor);
    double marketMultiplier = getMarketMultiplier(role, specialty);
    double careerStageMultiplier = getCareerStageMultiplier(age, experience);
    double performanceMultiplier = calculatePerformanceMultiplier(popularity, artisticCreativity, productivity, role);

    double finalSalary = baseSalary * marketMultiplier * careerStageMultiplier * performanceMultiplier;

    // Variação de ±8%
    double marketVariation = 0.92 + (Math.random() * 0.16);
    finalSalary *= marketVariation;

    return BigDecimal.valueOf(finalSalary).setScale(2, RoundingMode.HALF_UP);
}

Considerações Finais

Ainda tenho muito para desenvolver:

  • Implementar o sistema de contratos.
  • Lógica de Oferta/Demanda que afete salários dinamicamente.
  • Lógicas mais elaboras para representar os atributos de uma pessoa.
  • Personalidade influenciando atributos.

Nota: O salário base aqui representa o valor "mínimo" que um profissional aceitaria, mas esse valor pode ser negociado dependendo do tipo de contrato, duração e benefícios.

Queria saber a opinião de vocês:

  • O que vocês acham da modelagem?
  • Ideias de atributos ou mecânicas interessantes?
  • Alguma referência legal de simulação que eu deveria estudar?

Obrigado se leu até aqui! 😄