Trilhas
/
C++
C++
/
Exercícios
/
Trollar os trolls
Trollar os trolls

Trollar os trolls

Exercício de aprendizagem

Introdução

Enumerações

Até agora, lidamos principalmente com números e strings. Para modelar o mundo real, podemos querer um número limitado de valores que uma variável pode assumir. Talvez você queira um tipo dedicado, com alguns valores distintos e nomes distintos. Por exemplo, numa fábrica de skates, ter o material do shape como uma escolha entre apenas maple, bamboo ou plastic.

Você poderia usar inteiros para codificar esses valores, mas teria que usar código extra para verificar se o sistema está enviando um valor inválido para o material. O significado desses números mágicos é difícil de rastrear ao longo do código-fonte, e eles são propensos a confusões. enumerations podem ser usadas para incentivar um código expressivo e para restringir comparações acidentais.

Exemplo de uso

O termo específico para esse tipo de enumeração é scoped enumeration. O trecho abaixo mostra como escrever um enumeration DeckMaterial. Repare na palavra-chave enum class e no ; no final da definição:

enum class DeckMaterial {
    maple,
    bamboo,
    plastic
};

Agora, veja uma função de preços na loja de skates e repare no operador de resolução de escopo (::) especificando um enumerator do enumeration:

double deck_price(double base_price, DeckMaterial material) {
    if(material == DeckMaterial::plastic) {
        return base_price * 0.9;
    }
    return base_price * 1.3;
}

Escopo

Imagine que você tem um segundo enumeration para o material da roda:

enum class WheelMaterial {
    steel,
    clay,
    plastic
};

Embora as rodas e o shape possam ser feitos de plastic, os dois não podem ser confundidos. Eles são tipos diferentes: DeckMaterial plastic e WheelMaterial plastic. Cada enumeration terá seus enumerators em seu próprio escopo: o próprio namespace. É por isso que eles são chamados de scoped enumerations.

Advanced

Enumerações sem escopo

Você pode estar pensando que, com um nome como scoped, também existiriam enumerações unscoped, e você está certo. As Unscoped enumerations estão se tornando menos populares porque todas compartilham o mesmo namespace global. Por causa desse compartilhamento, você não poderia ter duas unscoped enumerations com os mesmos enumerators, como plastic no exemplo acima.

Além disso, unscoped enumerations são convertidas implicitamente para inteiros. Veja o exemplo abaixo, com um resultado surpreendente:

enum CitrusFruits {
    lemons,  // 0
    oranges, //1
};

enum IceCream {
    walnut,  // 0
    apples,  // 1
};

bool comparison{apples == oranges};
// => true

// Example from above:
bool comparison{DeckMaterial::plastic == WheelMaterial::plastic};
// => Does not compile!

Se você quiser converter scoped enumerations para inteiros, pode usar static_cast<int>.

Instruções switch

Assim como outras linguagens, C++ também oferece uma instrução switch. As instruções switch são uma maneira mais curta de escrever longas instruções if ... else if. Para criar um switch, começamos usando a palavra-chave switch seguida de um inteiro. Depois, declaramos cada uma das condições com a palavra-chave case. Também podemos declarar um caso default, que será executado quando nenhuma das condições case anteriores corresponder. Cada caso deve terminar com uma instrução break (ou return).

int price{0};
int adults{3};
int kids{2};

switch (int group_size{adults + kids}) {
    case 1:
        price = 50;
        break;
    case 2:
        price = 70;
        break;
    default:
        price = group_size * 30;
}

Continuação da execução

Um ponto importante sobre a construção switch é que o código continua a ser executado até ser interrompido por uma instrução break (ou return). Isso pode levar a um comportamento inesperado.

int adults{1};
int kids{0};
switch (int group_size{adults + kids}) {
    case 1:
        price = 50;
    case 2:
        price = 70;
    default:
        price = group_size * 30;
}
// price will be 30!

O principal uso desse recurso de execução continuada é uma instrução com vários rótulos. Vários resultados de um switch podem apontar para o mesmo trecho de código a ser executado. Assim, num aplicativo de reservas, por exemplo, a função chamada para grupos de tamanho 2 e 3 pode ser a mesma:

switch (group_size) {
case 1:
    book_room();
    break;
case 2:
case 3:
    book_apartment(group_size);
    break;
default:
    book_house(group_size);
}
// book_apartment happens when group_size is 2 or 3

Instruções

Sua amiga Helma fez um pequeno jogo online que rapidamente ganhou popularidade. Ele se chama HellMath. A pequena comunidade atraiu alguns trolls que deixam o jogo e os fóruns bem desagradáveis. Helma pediu para você trabalhar em um novo sistema de permissões para separar os encrenqueiros.

O fórum oferece três ações diferentes:

  • Ler
  • Escrever
  • Remover

Existem quatro tipos de conta, cada um com permissões padrão diferentes:

  • Convidados: podem ler posts.
  • Usuários e trolls: podem ler e escrever posts.
  • Moderadores: podem ler, escrever e remover posts, eles têm todas as permissões.

Helma percebeu que não adianta banir contas de troll. A estratégia dela é dar a eles a ilusão de que seu tempo é "bem investido", mas os posts deles só são mostrados para outros trolls. Em qualquer coisa que exija ordenação de prioridade, os trolls ficam por último em qualquer sequência. Quando entram em um jogo, o grupo de jogadores disponíveis também fica limitado a outros trolls.

Essa prática se chama banimento oculto.

1. Configure os tipos de usuário e as permissões.

Primeiro, defina uma enumeração AccountStatus para representar os quatro tipos de conta: troll, guest, user e mod.

Em seguida, defina uma enumeração Action para representar os três tipos de permissão: read, write e remove.

2. Promova trolls apenas para outros trolls.

Cada post nos fóruns salva o AccountStatus de quem postou nos seus metadados. Certifique-se de que posts de trolls sejam exibidos apenas para outros trolls.

Helma precisa de uma função display_post, que recebe dois argumentos do tipo AccountStatus e retorna um bool. O primeiro argumento é o status de quem postou, o segundo é o status de quem visualiza.

using namespace hellmath;
display_post(AccountStatus::troll, AccountStatus::user);
// => false
display_post(AccountStatus::mod, AccountStatus::guest);
// => true

3. Verifique as permissões de diferentes usuários.

Helma precisa de uma forma de verificar se uma determinada ação é permitida para um usuário.

Implemente uma função permission_check, que recebe uma Action como primeiro argumento e um AccountStatus para verificar. Ela deve retornar um bool de acordo com as permissões listadas na introdução.

permission_check(Action::remove, AccountStatus::guest);
// => false
permission_check(Action::write, AccountStatus::mod);
// => true

4. Conceda acesso ao jogo e emparelhe jogadores.

Para manter os jogadores de verdade responsáveis por suas ações no jogo, Hellmath nega o acesso aos convidados. Como mencionado acima, Helma quer que os trolls atormentem outros trolls. As conexões de jogo entre os outros usuários não têm restrições.

Implemente a função valid_player_combination, que verifica se dois jogadores podem entrar no mesmo jogo. A função tem dois parâmetros do tipo AccountStatus e retorna um bool.

valid_player_combination(AccountStatus::guest, AccountStatus::mod);
// => false
valid_player_combination(AccountStatus::troll, AccountStatus::troll);
// => true

5. Monte a fila de prioridades.

Com o crescimento enorme do jogo e dos fóruns, Helma agora precisa distribuir poder de processamento e largura de banda entre os usuários. Para lidar com emergências, os moderadores recebem a prioridade mais alta. Os convidados ficam na fila atrás dos usuários normais, e os trolls ficam atrás de todo mundo.

Implemente a função has_priority, que recebe dois argumentos AccountStatus e retorna true se, e somente se, a primeira conta tiver uma prioridade estritamente maior que a segunda.

has_priority(AccountStatus::guest, AccountStatus::mod);
// => false
has_priority(AccountStatus::user, AccountStatus::troll);
// => true
Editar via GitHub O link abre em uma nova janela ou aba
C++ Exercism

Tudo pronto para começar Trollar os trolls?

Crie sua conta no Exercism para aprender e dominar C++ com 19 conceitos100 exercícios e mentoria humana de verdade, tudo de graça.