Projeto: automatizar confecção da escala de serviço

Olá! Eu li o livro Orientação a Objetos, de Thiago Leite e Carvalho e agora estou tentando utilizar os conceitos que aprendi no meu projeto pessoal. Sou programador por hobby e estudo Python há 1 ano.

Aqueles que puderem e quiserem ajudar, por favor não escrevam código para mim. Apenas me mostrem o caminho, pois eu quero aprender programação. Obrigado! :wink:

Para acompanhar, as imagens estão no arquivo abaixo (só posso mandar 1 foto no post, por ser novo usuário :cry:):

Em Python, quero desenvolver o seguinte programa para automatizar a escala de serviço no meu setor de trabalho:

Eis algumas considerações:

  1. Todo dia tem 1 piloto de serviço;
  2. Existem 4 tipos de “quadrinhos” que devem ser computados: escala preta (dia útil - exceto o último da semana), escala vermelha (final de semana), escala amarela (último dia útil da semana) e escala roxa (carnaval, natal e ano novo);
  3. Em dias úteis, a troca do serviço ocorre 12h. O piloto que assume o serviço 12h passa o serviço 12h do dia seguinte;
  4. Em dias não úteis, a troca do serviço ocorre 8h.

O programa deve:

  1. escalar 1 piloto por dia, de acordo com os quadrinhos (quem tem menos quadrinho tem prioridade para ser escalado) e de acordo com a antiguidade (se os quadrinhos estiverem iguais, o piloto mais moderno tem prioridade para ser escalado);
  2. antes de escalar o piloto, o programa deve, além de considerar os quadrinhos, considerar a tabela de indisponibilidade. O usuário deve inserir a indisponibilidade dos pilotos e o programa não pode escalar um piloto indisponível para aquele dia;
  3. o programa deve, preferencialmente, dar um intervalo de 2 dias para escalar o mesmo piloto novamente, independente dos quadrinhos/antiguidade - a não ser que não exista mais pilotos disponíveis para o serviço;
  4. a escala é confeccionada todo fim de mês, para o mês seguinte;
  5. o programa deve gerar um relatório com a escala de serviço para o mês solicitado.

Basicamente é isso. Eu quero aprender mais sobre programação desenvolvendo esse projeto.

Tentando explicar exatamente como o programa trabalha:
:one: Nesse exemplo, o programa deve escalar a primeira semana de abril. Considere que temos 4 pilotos (AAA, BBB, CCC e DDD) e que nenhum piloto tem quadrinho ainda, todos estão “zerados” ou empatados (com a mesma quantidade de quadrinhos). As entradas seriam: os pilotos, a quantidade de quadrinhos de cada piloto, a indisponibilidade de cada piloto e o tipo de serviço (de acordo com o dia - sexta-feira = amarelo, final de semana = vermelho e segunda a quinta = preto). A ordem de antiguidade é a seguinte: o piloto AAA é mais moderno que o BBB, que é mais moderno que o CCC que é mais moderno que o DDD (mais moderno entenda-se que ele é inferior na hierarquia militar). O resultado (a saída) da primeira semana seria:
imagem semana 1

Processos:

  1. o primeiro serviço é escala amarela (sexta-feira). Então o programa deve consultar a quantidade de quadrinhos amarelos de todos os pilotos. No nosso exemplo, eles estão iguais (zero). Na sequência, o programa deve consultar a indisponibilidade de todos os pilotos. No nosso exemplo, nenhum piloto está indisponível nessa semana. Dessa forma, o programa seleciona o piloto mais moderno (ordem de antiguidade) e aloca para aquele dia. No nosso caso, o programa deve escalar o piloto AAA;
  2. o próximo serviço é escala vermelha (sábado). Todos os pilotos estão iguais nos quadrinhos vermelhos e não há indisponibilidade. Logo, o piloto AAA (mais moderno) deveria ser escalado. Mas, como ele já está de serviço no dia anterior, o próximo a ser escalado é o BBB (deve haver, preferencialmente, um intervalo de 48 horas entre os serviços de um mesmo piloto);
  3. o próximo também é escala vermelha (domingo). Agora, o piloto BBB já tem 1 quadrinho vermelho e os demais não tem nada. Logo, o piloto AAA deveria ser escalado, mas como ele está na sexta-feira (inferior a 48 horas), o piloto CCC é o escalado;
  4. na segunda-feira, dia útil, a escala é a preta. Todos os pilotos estão com 0 quadrinho preto, logo o piloto AAA é o escalado, pois agora já se respeita o intervalo de 48h desde o seu último serviço, na sexta-feira;
  5. e assim vai, sucessivamente, para os próximos dias de escala preta;
  6. na próxima sexta-feira, dia 7/4, a escala é amarela. Ao consultar os quadrinhos amarelos, o piloto AAA possui 1 quadrinho e os demais possuem 0. Logo, o próximo piloto na antiguidade, BBB, é o escalado.

Ao final da primeira semana, teríamos o seguinte controle de quadrinhos dos pilotos:
imagem controle 1


:two: Na segunda semana de abril, continuando os processos, teríamos:

  1. o próximo serviço é escala vermelha (sábado). Ao consultar os quadrinhos, os pilotos AAA e DDD possuem 0 quadrinho vermelho e os pilotos BBB e CCC possuem 1 quadrinho. Logo, pela antiguidade, o piloto AAA é escalado para o sábado e o piloto DDD é escalado para o domingo;
  2. para o serviço de segunda-feira, escala preta, o programa consulta os quadrinhos pretos e verifica que todos possuem 1 quadrinho, ou seja, estão empatados. Logo, o piloto AAA deveria ser escalado. Porém, para respeitar as 48h, o programa passa para o próximo piloto na ordem de antiguidade: BBB;
  3. na terça feira, o programa verifica que o piloto BBB possui 2 quadrinhos e todos os outros possuem 1 quadrinho. Logo, o piloto AAA é escalado, já que agora as 48h são respeitadas;
  4. na quarta-feira, o programa escala o piloto CCC e na quinta, o piloto DDD;
  5. na sexta-fiera, escala amarela, o programa checa os quadrinhos: AAA e BBB possuem 1 quadrinho amarelo e CCC e DDD possuem 0. Deveria escalar o piloto CCC, mas para respeitar as 48h, passamos para o próximo DDD, que também não pode ser escalado por causa das 48h. Logo, o piloto AAA é escalado. Se o piloto AAA tivesse 2 quadrinhos amarelos e o piloto BBB tivesse apenas 1, o piloto BBB seria escalado.
    A saída da segunda semana seria:
    imagem semana 2
    Agora, o controle de quadrinhos estaria da seguinte forma:
    imagem controle 2

:three: para a terceira semana, consideremos que o piloto AAA está indisponível do dia 15/4 a 30/4, por motivo de viagem:

  1. para o sábado, ao consultar os quadrinhos vermelhos, o programa verifica que todos possuem 1 quadrinho. Logo, o piloto AAA deveria ser escalado. Como ele está indisponível, o programa escala o próximo piloto: BBB. Observe que, mesmo que o piloto AAA estivesse disponível, ele não poderia ser escalado, por causa das 48h;
  2. para o domingo, seguindo a mesma lógica, o programa escala o piloto CCC;
  3. para a segunda-feira, escala preta, o programa verifica que todos os pilotos possuem 2 quadrinhos. Logo, o piloto AAA deveria ser escalado. Como ele está indisponível, o programa passa para o próximo BBB. Agora, afeta a regra das 48h, tanto para o BBB quanto para o CCC. Logo, o programa escala o piloto DDD. Observe que, se o piloto DDD também estivesse indisponível, o programa escalaria o piloto BBB mesmo desrespeitando a regra das 48h (deve haver 48h entre os serviços, preferencialmente);
  4. terça-feira, escala preta: o piloto AAA está indisponível, passa para o pŕoximo: CCC;
  5. na quinta-feira, o programa verifica que os pilotos BBB, CCC e DDD possuem 3 quadrinhos pretos e o piloto AAA possui 2 quadrinhos pretos. Como AAA está indisponível, o programa seleciona o próximo: BBB. Como afeta a regra das 48h, tanto para BBB quanto para CCC, o programa escala o piloto DDD;
  6. na sexta-feira, escala amarela, o programa verifica que o piloto AAA possui 2 quadrinhos, BBB possui 1 quadrinho e os pilotos CCC e DDD possuem 0. Logo, deveria escalar o piloto CCC. Para respeitar a regra das 48h - tanto para CCC quanto para DDD, o programa escala o piloto BBB, que possui menos quadrinhos que AAA, além do AAA estar indisponível.
    A saída seria:
    imagem semana 3
    Ao final, teríamos o seguinte controle de quadrinhos:
    imagem controle 3

Tentando aplicar o que li no livro Orientação a Objetos, desenhei a seguinte modelagem para o sistema:
imagem diagrama

Isso está certo? Alguém teria alguma crítica/sugestão?

Comecei a escrever o código. Inicialmente apenas defini os atributos das classes, seguindo o diagrama de modelagem.
Mas não sei está legal. Será que não seria melhor apenas uma classe Piloto com todos os atributos e, em separado, uma classe Escala?

Do jeito que está, por exemplo, a classe Post gera um objeto que corresponde a uma lista de 6 itens (2º Ten, 1º Ten, Cap, Maj, TCel e Cel), quando na verdade eu gostaria que apenas 1 desses itens fosse o estado de um dos atributos do objeto da classe Pilot, no caso o atributo post.

Qual seria a melhor estrutura?

Github.

    class Post:
        """define os postos militares: 2º Ten, 1º Ten, Cap, etc"""

        posts = ["2º Ten", "1º Ten", "Cap", "Maj", "TCel", "Cel"]

        def __init__(self):
            self.post = [post for post in self.posts]

        def __getitem__(self, item):
            return self.post[item]

        def __len__(self):
            return len(self.post)

    post = Post()


    class Unavailability:
        """define períodos de indisponibilidade"""

        def __init__(self, begin, end, reason):
            self.begin = begin
            self.end = end
            self.reason = reason

        #TODO = criar métodos



    class Point:
        """define o tipo de 'quadrinho' da escala de serviço"""

        colors = ["preta", "vermelha", "amarela", "roxa"]

        def __init__(self):
            self.color = [color for color in self.colors]

        def __getitem__(self, item):
            return self.color[item]

    point = Point()


    class Service(Point):
        """define a data do serviço"""

        def __init__(self, color, date):
            self.color = color
            self.date = date
            super(Service, self).__init__()


    class Ballast(Point):
        """define lastros de serviço"""

        def __init__(self, color, quantity, cause):
            self.color = color
            self.quantity = quantity
            self.cause = cause
            super(Ballast, self).__init__()


    class Pilot:
        """define os pilotos"""

        def __init__(self, post, name, trigram, unavailabilities, services, ballasts):
            self.post = post
            self.name = name
            self.trigram = trigram
            self.unavailabilities = unavailabilities
            self.services = services
            self.ballasts = ballasts

        def __str__(self):
            return self.trigram

        # TODO = criar métodos


    class Rank:
        """define a antiguidade entre os pilotos"""

        def __init__(self, rank, trigram):
            self.rank = rank
            self.trigram = trigram

        # TODO = criar métodos


    class Schedule:
        """define a escala de serviço"""

        def __init__(self, date, trigram):
            self.date = date
            self.trigram = trigram

        #TODO = criar métodos