Skip to content

Latest commit

 

History

History
1096 lines (849 loc) · 35.7 KB

01.md

File metadata and controls

1096 lines (849 loc) · 35.7 KB

Revisão de LP1

Nota 1: Poderá ser boa ideia também rever os Exercícios de LP1.

Nota 2: Nos exercícios com imagens, as imagens devem ser guardadas em modo Git LFS na pasta solucoes/01/ e devem ter como nome o número do exercício.

Problemas

1 - Escreve um programa que aceite dois ou mais números inteiros como parâmetros na linha de comandos, coloque esses números num array de ints e apresente ao utilizador um menu com as seguintes opções:

  1. Obter média dos valores no array
  2. Obter mediana dos valores no array
  3. Obter moda dos valores no array
  4. Obter máximo dos valores no array
  5. Obter mínimo dos valores no_array
  6. Sair

O programa deve funcionar em ciclo, realizando os pedidos efetuados, terminando apenas quando o utilizador selecionar a opção 6.

Soluções


2 - Escreve um programa que realize a multiplicação entre uma matriz n x m e um vetor m x 1. O programa deve começar por solicitar as dimensões n e m, pedindo depois ao utilizador que preencha os valores da matriz e do vetor a multiplicar, e finalmente mostrando o resultado final na forma de um vetor n x 1.

Nota 1: Este exercício deve ser resolvido com recurso a arrays multidimensionais.

Nota 2: A resolução deste exercício depende da matéria de multiplicação de matrizes (disciplina de Introdução à Matemática e Física para Jogos I).

Nota 3: Podes experimentar multiplicar uma matriz por um vetor online em http://matrix.reshish.com/multiplication.php.

Soluções


3 - Indica o que é mostrado no ecrã pelo seguinte código C#. Justifica a tua resposta.

byte b = byte.MaxValue - 1;

for (int i = 0; i < 5; i++)
{
    Console.WriteLine($"Iteração {i}: {(byte) (++b - 1)}");
}

Soluções


4 - Indica o que é mostrado no ecrã pelo seguinte código C#. Justifica a tua resposta.

int[] someInts = { 11, 8, 6, 3, 9, 104 };

foreach (int v in someInts)
{
    if (v % 2 == 0)
    {
        Console.WriteLine("{0,3}", v);
    }
}

Soluções


5 - Considera a seguinte declaração do método Next (classe Random, namespace System):

public virtual int Next(int minValue, int maxValue);

Indica:

  1. O nome do método.
  2. O tipo devolvido pelo método.
  3. Os argumentos aceites pelo método.
  4. A assinatura do método.
  5. Outras características indicadas na declaração.
  6. Se existe algum overload deste método na classe Random, e em caso afirmativo, mostrar as respetivas declarações.

Soluções


6 - Considera o método Recursao():

static int Recursao(int n1) {
    int n2;
    if (Math.Abs(n1) > 1000) {
        n2 = n1;
    } else {
        n2 = Recursao(-n1 * 10);
    }
    return n2;
}

Considera a seguinte invocação do método Recursao():

int n0 = Recursao(5);

Qual é o valor da variável n0 após a linha de código anterior? Explica o teu raciocínio.

Nota 1: O método Abs da classe Math (namespace System) devolve o valor absoluto (módulo) do valor passado como argumento.

Soluções


7 - Indica o que é impresso no ecrã pelo seguinte código. Justifica a tua resposta, explicando em que consiste a operação efetuada pelo método GCD().

static void Main(string[] args)
{
    ulong a = Convert.ToUInt64(args[0]);
    ulong b = Convert.ToUInt64(args[1]);
    Console.WriteLine($"GCD between {a} and {b} is {GCD(a, b)}");
}

static ulong GCD(ulong a, ulong b) => b == 0 ? a : GCD(b, a % b);

Soluções


8 - Qual é o valor da variável x após as seguintes instruções. Explica o teu raciocínio.

double x = 11.09;
AddOne(x);

Soluções


9 - Cria uma classe chamada Checker com um único método de nome Check(). Este método recebe dois argumentos: 1) um array bidimensional de int; e, 2) um int. O método retorna true caso encontre uma linha (horizontal, vertical ou diagonal) de quatro ou mais inteiros iguais ao 2º argumento, ou false caso contrário.

Adiciona o método estático Main() à classe Checker. Este método deve: 1) solicitar ao utilizador as dimensões do array; 2) solicitar ao utilizador os valores do array; 3) solicitar ao utilizador o valor a procurar no array; 4) criar uma nova instância de Checker; 5) invocar o respetivo método Check() para verificar se o valor a procurar no array aparece em forma uma linha com comprimento igual ou maior a quatro; e, 6) indicar no ecrã se essa linha existe ou não.

Soluções


10 - No exercício anterior faria sentido a respetiva classe e o seu único método serem static? Porquê?

Soluções


11 - Qual a diferença prática entre as keywords override e new na declaração de um método? Dá um exemplo. Nota: se o exemplo for retirado de algum lado não te esqueças de incluir a referência.

Soluções


12 - Quais as diferenças entre as coleções não-genéricas e as coleções genéricas no C#? Quais as vantagens destas últimas?

Soluções


13 - O C# providencia um conjunto bastante completo de coleções genéricas. Algumas das mais usadas são as que se seguem:

Responde às seguintes questões:

  1. Qual a interface genérica comum a todas estas coleções? Que comportamento ficam as classes obrigadas a ter devido a implementarem essa interface?
  2. Explica sucintamente como estas coleções funcionam e dá exemplos onde cada uma seja especialmente útil.
  3. Além das coleções mencionadas, existem mais coleções genéricas no namespace System.Collections.Generic. Dá o exemplo de uma, explica sucintamente como funciona e dá um exemplo onde a mesma possa ser especialmente útil.

Soluções


14 - Considera o seguinte tipo:

public struct GameMap
{
    private float topScore;
    private int gamesPlayed;
    private int gamesWon;

    public string Name { get; }
    public string Filename { get; }
    public float SuccessRate
    {
        get {
            if (gamesPlayed == 0)
                return 0f;
            else
                return gamesWon / (float) gamesPlayed;
        }
    }
    public float TopScore {
        get
        {
            return topScore;
        }
        set
        {
            if (value > topScore)
            {
                topScore = value;
            }
        }
    }

    public GameMap(string name, string filename)
    {
        Name = name;
        Filename = filename;
        gamesPlayed = 0;
        gamesWon = 0;
        topScore = 0;
    }

    public void GamePlayed(bool won)
    {
        gamesPlayed++;
        if (won)
        {
            gamesWon++;
        }
    }
}

Responde às seguintes questões relativas ao tipo apresentado:

  1. O tipo apresentado é de valor ou referência? Justifica a tua resposta.
  2. Identifica as variáveis de instância e explica o seu propósito.
  3. Identifica as propriedades auto-implementadas.
  4. Identifica as propriedades só de leitura.
  5. Identifica os construtores.
  6. Identifica os métodos de instância.
  7. Escreve a documentação XML apropriada para a classe e respetivos membros.
  8. Escreve um método static que recebe um iterável de GameMap e imprime uma tabela bem formatada com informação sobre os mesmos, tal como representado na seguinte figura:
Name              Filename      Sucess Rate    Top Score
--------------------------------------------------------
Hell              hell.map           30.2 %     5069.921
Beach             beach.map          44.0 %     2231.887
Valley            valley.map         72.1 %      131.090
Work              work.map           44.4 %     2334.114
School            school.map         11.5 %       40.587
Graveyard         graveyard.map      69.8 %     1631.103
Mars              mars.map           92.1 %     2257.178

Soluções


15 - Cria uma struct imutável, de nome Duration, que representa um intervalo de tempo, tendo as seguintes propriedades: Seconds, Minutes, Hours, Days, Weeks e Years. Cria também um programa para testar diferentes instâncias desta struct, e responde às seguintes questões:

  1. Quais são as vantagens desta struct ser imutável?
  2. Podemos usar a sintaxe de inicialização de objetos com propriedades para inicializar instâncias desta struct? Porquê?

Soluções


16 - Quais são os requisitos para que uma classe possa ser instanciada usando a sintaxe de inicialização de coleções?

Soluções


17 - Quais são os requisitos para que uma instância de uma classe possa ser usada num foreach como fornecedor de itens?

Soluções


18 - Considera a seguinte classe:

public class Weapon
{
    public float AttackPower { get; }
    public float Durability { get; }

    public Weapon(float attackPower, float durability)
    {
        AttackPower = attackPower;
        Durability = durability;
    }
}

Assume que temos uma lista de armas, ou seja, uma variável do tipo List<Weapon> e responde às seguintes questões:

  1. Faz as alterações necessárias à classe Weapon de modo a que quando invocarmos o método Sort (ou mais concretamente, o seu overload sem parâmetros) da classe List<T>, as instâncias de Weapon fiquem ordenadas por AttackPower decrescente. Sugestão: a classe Weapon tem de implementar IComparable<T>.
  2. Cria uma classe Program com um método Main() para testar uma lista de várias instâncias de Weapon, nomeadamente a sua ordenação por AttackPower decrescente usando o método Sort() sem parâmetros.
  3. O método Sort da classe List<T> tem vários overloads. Um deles, Sort(IComparer<T>), permite ordenar a lista usando o critério de ordenação definido numa classe extra. Tal classe, como indicado na assinatura do método, tem de implementar a interface IComparer<T>. Cria uma classe deste tipo cujo critério de ordenação seja Durability crescente.
  4. Adiciona ao método Main() da classe Program um teste à ordenação por Durability crescente usando o método Sort(IComparer<T>) e a classe desenvolvida no ponto anterior.

Soluções


19 - Considera a seguinte classe:

public class SpaceFleet
{
    private Spaceship[] spaceships;

    public SpaceFleet() { /* Código do construtor aqui */ }

    public Spaceship GetSpaceship(int i)
    {
        if (i < spaceships.Length)
            return spaceships[i];
        else
            return null;
    }

    public bool SetSpaceship(int i, Spaceship spaceship)
    {
        if (i < spaceships.Length && spaceships[i] == null)
        {
            spaceships[i] = spaceship;
            return true;
        }
        return false;
    }
}
  1. O tipo Spaceship é de referência (classe) ou de valor (struct ou enum)? Porquê?
  2. A classe está a usar métodos getter e setter. Não seria preferível usar uma propriedade? Justifica a tua resposta.

Soluções


20 - Considera a seguinte classe:

public class Enemy
{
    public static int NumberOfEnemies { get; private set; }
    public int Health { get; set; }

    public Enemy(int health)
    {
        NumberOfEnemies++;
        Health = health;
    }

    public void Die()
    {
        NumberOfEnemies--;
        Health = 0;
    }
}

Responde às seguintes questões:

  1. Considera que monster é uma instância de Enemy. Escreve duas linhas de código, uma para imprimir no ecrã a propriedade Health da instância, outra para imprimir a propriedade NumberOfEnemies da classe.
  2. Porque razão faz sentido a propriedade NumberOfEnemies ser static?
  3. De que parte do código pode ser alterado o valor da propriedade NumberOfEnemies?

Soluções


21 - Considera o seguinte código:

public class Power
{
    public string Description { get; set; }
    public int Range { get; set; }
}

public class PlayerClass
{
    private int health;
    private int shield;
    private List<Power> powers;

    public PlayerClass(int health, int shield)
    {
        this.health = health;
        this.shield = shield;
        powers = new List<Power>();
    }

    public void AddPower(Power p)
    {
        powers.Add(p);
    }
}

public struct PlayerStruct
{
    private int health;
    private int shield;
    private List<Power> powers;

    public PlayerStruct(int health, int shield)
    {
        this.health = health;
        this.shield = shield;
        powers = new List<Power>();
    }

    public void AddPower(Power p)
    {
        powers.Add(p);
    }
}

Pretende-se que os tipos PlayerClass e PlayerStruct implementem a interface ICloneable, de modo a que uma chamada ao respetivo método Clone() devolva uma cópia profunda da instância em questão. Uma cópia profunda consiste numa nova instância cujos campos têm o mesmo valor do objeto original. Se algum dos campos for um tipo de referência, a instância associada deve também ser clonada da mesma forma, e por ai fora. Reescreve o código dos tipos PlayerClass e PlayerStruct de modo a que implementem ICloneable segundo estas especificações.

Soluções


22 - Considera a seguinte classe:

public abstract class GameItem
{
    public readonly string name;
    public readonly string description;

    public GameItem(string name, string description)
    {
        this.name = name;
        this.description = description;
    }
}

Responde às seguintes questões:

  1. Implementa a classe Sword que estende GameItem, tendo adicionalmente como estado os campos length, typeOfMetal e condition. O primeiro pode ser representado com um número real, e os outros têm um tipo próprio, TypeOfMetal e WeaponCondition, respetivamente. O construtor de Sword aceita 5 parâmetros, que são usados para inicializar todos os campos da classe. No entanto, os campos herdados de GameItem devem ser inicializados pelo respetivo construtor.
  2. Cria as enumerações TypeOfMetal e WeaponCondition com valores à tua escolha mas de modo a que façam sentido no contexto do problema.
  3. Dá um exemplo em código de como podemos criar uma instância de Sword.
  4. Normalmente as variáveis de instância têm visibilidade privada de modo a não comprometer a encapsulação. No entanto não é esse o caso no código apresentado. Porque razão a quebra de encapsulação não é tão grave neste caso?
  5. Podemos instanciar diretamente GameItem? Porquê?

Soluções


23 - Considera a seguinte interface:

public interface ILightSource
{
    double Illuminance { get; }
}

Cria a classe Star que implementa as interfaces ILightSource e IComparable<T>. A propriedade Illuminance da classe Star é obtida com a seguinte fórmula:

I = d * A * T4

na qual d é a constante de Stefan–Boltzmann (com um valor de 5.670 x 10−8), A é a área de superfície da estrela e T é a temperatura média da estrela. O construtor de Star aceita como parâmetros iniciais A e T, que não mudam durante o tempo de vida da estrela.

O critério de ordenação quando várias instâncias de Star são ordenadas segue a área de superfície (decrescente, da maior para a mais pequena), e em caso de estrelas com a mesma área, a temperatura serve como critério de desempate (também decrescente).

Soluções


24 - A API do C# contém uma coleção especializada na manipulação de booleanos (zeros e uns). Faz uma pesquisa para descobrires que coleção é essa e realça algumas das suas principais funcionalidades, nomeadamente vantagens sobre o uso de um simples array de booleanos.

Soluções


25 - Dá três exemplos de coleções genéricas do C# que implementem ICollection<T>. Qual é ou quais são as funcionalidades que as coleções que implementam esta interface são obrigadas a ter?

Soluções


26 - Considera as interfaces IList<T> e IDictionary<TKey,TValue> .

  1. Para cada uma das interfaces, dá um exemplo de uma coleção do C# que a implemente.
  2. Qual é ou quais são as funcionalidades que as coleções que implementam estas interfaces são obrigadas a ter?

Soluções


27 - Indica três coleções da API do C# que suportem sintaxe de inicialização de coleções e dá um exemplo de uso para cada uma delas.

Soluções


28 - Considera os tipos MonsterType e Monster, definidos pelo seguinte código:

enum MonsterType { Troll, Ogre, Elf, Demon }
class Monster
{
    public const double MaxHealth = 100;
    public const int MaxStrength = 200;
    public MonsterType Type { get; set; }
    public double Health { get; set; }
    public int Strength { get; set; }
}

Responde às seguintes questões:

  1. Existe algum campo static (de classe) na classe Monster?
  2. Adiciona o método iterável CreateRandomMonsters() à classe Monster, que recebe um inteiro n indicando quantos monstros devem ser criados, e que devolve um IEnumerable<Monster> de n monstros com campos inicializados aleatoriamente (dentro dos limites especificados nos tipos).
  3. O método CreateRandomMonsters() deve ser static? Justifica a tua resposta.
  4. Faz override do método ToString() na classe Monster de modo a que o mesmo devolva uma string indicando, de forma bem formatada, as várias propriedades do monstro. Por exemplo, a propriedade Health não deve ter mais de duas casas decimais.
  5. Cria a classe Program com um método Main para testares a criação de 20 monstros aleatórios com o método CreateRandomMonsters(), imprimindo no ecrã a string devolvida pelo método ToString() para cada monstro.

Soluções


29 - Escreve um programa que comece por solicitar ao utilizador dois conjuntos de números inteiros, conjunto 1 e conjunto 2. O programa deve depois apresentar os resultados das seguintes operações:

  1. União - Operação de união entre os dois conjuntos, ou seja, elementos presentes no conjunto 1, no conjunto 2, e em ambos os conjuntos.
  2. Interseção - Operação de interseção entre os dois conjuntos, ou seja, elementos simultaneamente presentes no conjunto 1 e no conjunto 2.
  3. Diferença - Operação de diferença entre o conjunto 1 e o conjunto 2, ou seja, elementos do conjunto 1 exceto aqueles que também existam no conjunto 2.
  4. Diferença simétrica - Operação de diferença simétrica entre o conjunto 1 e o conjunto 2, ou seja, elementos que existam ou no conjunto 1 ou no conjunto 2, mas não em ambos os conjuntos.
  5. Subconjunto - Se o conjunto 1 é um subconjunto do conjunto 2, ou seja, se todos os elementos do conjunto 1 existem também no conjunto 2.
  6. Superconjunto - Se o conjunto 1 é um superconjunto do conjunto 2, ou seja, se o conjunto 1 contem todos os elementos do conjunto 2.

Os resultados das operações 1 a 4 devem aparecer de forma ordenada, e as operações devem ser independentes umas das outras, partindo sempre dos conjuntos 1 e 2 originais.

Este problema deve ser resolvido com recurso direto às funcionalidades oferecidas pelas coleções do C#.

Soluções


30 - Em alguns casos os dicionários podem ser usados para fins de caching, ou seja, para guardar resultados obtidos recentemente. Escreve um programa que leia a lista de jogos disponível aqui para um array de strings, e que solicite ao utilizador (em ciclo infinito) uma frase, que será comparada com todos os jogos no array. Para existir um match, basta que uma string que representa o nome de um jogo contenha a frase inserida pelo utilizador. A procura deve ser independente de maiúsculas e minúsculas. Após a procura, o programa deve indicar quantos jogos encontrou e quanto tempo demorou a fazer a procura. O seguinte código apresenta um template da solução:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

class Program
{
    static void Main(string[] args)
    {

        // Abrir ficheiro com nomes de jogos e colocar num array de strings
        string[] games = File.ReadAllLines("videogames.txt");

        // Ciclo de procuras, infinito
        while (true)
        {
            // Cronómetro
            Stopwatch stopwatch;
            // String a procurar
            string searchString;
            // Resultados da procura, têm de ser enumeráveis e contáveis
            ICollection<string> results;

            // Solicitar string de procura, transformar em minúsculas para
            // facilitar comparação mais à frente
            Console.Write("Search for? ");
            searchString = Console.ReadLine().ToLower();

            // Começar contagem do tempo
            stopwatch = Stopwatch.StartNew();

            // Realizar procura aqui e colocar resultados na variável results,
            // que provavelmente será uma lista. A procura deve:
            // - Ignorar strings vazias ou que comecem com cardinal #
            //   (que representa um comentário no ficheiro videogames.txt)
            // - Ser independente de maiúsculas e minúsculas

            // Parar o cronómetro
            stopwatch.Stop();

            // Mostrar resultados da procura
            Console.WriteLine($"Time to find {results.Count} games was" +
                $"{stopwatch.Elapsed}");

            // Opcionalmente podemos mostrar alguns ou todos os jogos
            // encontrados para fins de debugging
        }
    }
}

Cada vez que é feita uma procura é necessário percorrer todo o array de jogos novamente. No entanto a tua solução deve primeiro verificar se a procura já foi feita e existe em cache (i.e., num dicionário criado para o efeito). Caso a procura exista em cache, serão devolvidos os resultados previamente guardados. Caso contrário é percorrido novamente todo o array de jogos. Compara o tempo da procura no array para novas procuras com o tempo de procura no dicionário para pesquisas previamente efetuadas.

Sugestão: O dicionário deve ser do tipo Dictionary<string, ICollection<string>>, em que a chave representa a frase de procura e o valor representa os resultados dessa mesma procura.

Soluções


31 - Considera o tipos LootType e Loot:

public enum LootType { Health, Ammo, Shield, Weapon, Collectible }
public class Loot
{
    public LootType WhatKindOfLootAmI { get; set; }
    public string Description { get; set; }
    public ulong Value { get; set; }
}
  1. Faz override dos métodos GetHashCode() e Equals() de modo a que um loot seja considerado único no jogo se tiver o mesmo tipo, descrição e valor. Sugestão: Uma forma rápida de obter um hash code para um dado tipo consiste em realizar a operação XOR no hash code dos seus diferentes campos.
  2. Testa a tua solução colocando vários objetos do tipo Loot num conjunto, repetindo propositadamente os campos de duas instâncias diferentes.
  3. Se o tipo Loot fosse uma struct qual seria o comportamento por omissão relativamente à igualdade de instâncias? Era necessário ter feito os overrides na primeira alínea do exercício?

Soluções


32 - Quais são os requisitos para que uma instância de uma classe possa ser usada num foreach como fornecedor de itens?

Soluções


33 - Numa classe ou método genérico como podemos obrigar a que o tipo genérico tenha um construtor vazio?

Soluções


34 - Numa classe ou método genérico como podemos obrigar a que o tipo genérico seja um tipo de referência?

Soluções


35 - Numa classe ou método genérico como podemos inicializar o tipo genérico com o seu valor por omissão (equivalente a zero ou null)?

Soluções


36 - Existe uma class Random tanto na API do C# como na API do Unity, que podem respetivamente ser importadas com os seguintes using:

using System;
using UnityEngine;

Responde às seguintes questões:

  1. Como podemos diferenciar, no nosso código, entre o Random do C# e o Random do Unity?
  2. Qual a principal diferença entre as duas classes, do ponto de vista de instanciação e invocação dos métodos que produzem números aleatórios?

Soluções


37 - Considera a classe static Input do Unity. Responde às seguintes questões:

  1. O que é necessário para que uma classe seja static?
  2. Porque razão faz sentido a classe Input ser static?
  3. O que é necessário fazer para usarmos os métodos e propriedades da classe Input diretamente no nosso código, por exemplo, escrevermos GetButton() em vez de Input.GetButton()?
  4. Quais são os perigos de usar a abordagem indicada na pergunta anterior.
  5. Identifica mais duas classes static na API do Unity. Discute se faz sentido essas classes serem static.

Soluções


38 - Considera a seguinte classe:

using System.Collections;
using System.Collections.Generic;

public class BasketballTeam : IEnumerable<string>
{
    public string Guard { get; set; }
    public string ShootingGuard { get; set; }
    public string SmallForward { get; set; }
    public string PowerForward { get; set; }
    public string Center { get; set; }

    public IEnumerator<string> GetEnumerator()
    {
        yield return Guard;
        yield return ShootingGuard;
        yield return SmallForward;
        yield return PowerForward;
        yield return Center;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
  1. Cria uma classe Program com um método Main para testar a classe apresentada. Mais concretamente, no método Main deves: a) criar uma instância de BasketballTeam usando a sintaxe de inicialização de objectos com propriedades; e, b) imprimir no ecrã o nome de todos os elementos da equipa usando o facto da classe BasketballTeam ser iterável.
  2. Supõe que o C# não tem a declaração yield return. Reescreve o método GetEnumerator tendo em conta essa limitação.
  3. Quais são as vantagens óbvias do uso de yield return relativamente à forma como reescreveste o código na alínea anterior?

Soluções


39 - Escreve um método static que troque o valor de duas variáveis de entrada cujo tipo é definido em tempo de execução (ou seja, por quem invoca o método).

Soluções


40 - Cria uma classe IntList que estende List<int>, adicionando três versões de um método que retorne o valor mínimo (int), o valor máximo (int) e o valor médio (float) referentes aos inteiros contidos na lista. Cada versão do método deve retornar estes valores de forma diferente: 1) usando parâmetros de saída (out); 2) usando uma classe/struct específica; e, 3) usando tuplos. A segunda forma pressupõe a criação de uma classe ou struct extra; neste caso podem criar uma classe/struct interna, ou seja, dentro da classe IntList. Sobrepõe ainda o método ToString() de modo a que a string devolvida indique quantos elementos tem a lista, bem como os valores mínimo, máximo e médio contidos na mesma.

Soluções


41 - Cria uma classe chamada HighScoreManager, que contém internamente uma coleção com um máximo de 10 Tuple<string, float>, cada um representando o nome de um jogador e o respetivo score. Além da coleção referida, a classe deve ainda conter:

  • Um construtor, que aceita opcionalmente um nome de ficheiro (deve existir um nome por omissão), e:
    • Caso o ficheiro não exista, inicializa a coleção sem elementos.
    • Caso o ficheiro exista, abre-o e inicializa a coleção de modo a que contenha os nomes e scores especificados no ficheiro.
    • Caso o ficheiro exista, mas tenha um formato inválido, lançar uma excepção do tipo InvalidOperationException.
  • Um método AddScore(string name, float score), que adiciona um novo Tuple<string, float> à coleção. Se o número de scores ultrapassar 10, o tuplo contendo o menor score deve ser removido.
  • Um método Save(), que guarda os scores no ficheiro especificado no construtor.
  • Um método ToString(), que devolve uma string contendo uma tabela devidamente formatada com todos os nomes e scores, do mais alto ao mais baixo.
  • Um método iterável GetScores() que retorna de forma ordenada (do score mais alto até ao score mais baixo) todos tuplos guardados na coleção.

O formato do ficheiro de high scores fica ao critério dos alunos.

Cria também uma classe Program com um método Main para testar os vários métodos da classe HighScoreManager.

Soluções


42 - Cria uma classe, com um único método estático Main(), que solicita ao utilizador um número inteiro não-negativo e apresenta o respetivo número da sequência de Lucas. O número deve ser calculado de forma recursiva com uma ou mais funções locais.

Soluções


43 - Quais as vantagens e desvantagens do uso de out e ref na passagem de parâmetros para métodos?

Soluções


44 - A classe Array tem vários métodos utilitários static. Um deles tem uma série de overloads que fazem algo similar ao especificado no exercício anterior. Descobre qual é o nome deste método e utiliza um dos seus overloads para instanciar uma matriz (i.e., um array bidimensional) de 50 x 50 booleanos.

Soluções


45 - Considera a seguinte classe:

public abstract class NPC
{
    public float HP { get; protected set; }

    public NPC(float hp)
    {
        HP = hp;
    }

    public void PlayTurn()
    {
        if (FindEnemies())
        {
            AttackEnemies();
        }
        if (FindFood())
        {
            EatFood();
        }
        Move();
    }

    protected abstract bool FindFood();
    protected abstract bool FindEnemies();
    protected abstract void EatFood();
    protected abstract void AttackEnemies();

    protected virtual void Move()
    {
        Console.WriteLine(this.GetType() + " has moved!");
    }
}

Responde às seguintes questões:

  1. É possível instanciar esta classe? Porquê?
  2. É possível estender esta classe? Porquê?
  3. Que métodos desta classe podem ser sobrepostos (overridden)? Porquê?
  4. Que métodos desta classe não podem ser sobrepostos (overridden)? Porquê?
  5. Cria pelo menos 3 subclasses concretas (não abstratas), representando diferentes NPCs num jogo, com lógicas concretas e específicas para cada um deles. Os métodos EatFood() e AttackEnemies() podem consistir apenas de Console.WriteLines.
  6. Cria uma classe Program com um método Main() para testar as classes criadas no ponto anterior. Por exemplo, criar uma ou mais instâncias de cada classe, colocar as mesmas numa coleção de NPC, percorrer a coleção, e invocar o método PlayTurn() em cada uma delas. Repara que, além do construtor, só o método PlayTurn() pode ser invocado a partir de outras classes.
  7. Identifica a presença de polimorfismo na solução que apresentaste no ponto anterior.
  8. Desenha o diagrama UML da solução apresentada.

Soluções


46 - O exercício anterior corresponde a um design pattern muito útil e comum, que consiste em definir os passos principais de um algoritmo ou operação, delegando nas subclasses alguns ou todos os passos concretos do mesmo. Por outras palavras, este design pattern permite redefinir alguns passos do algoritmo ou operação sem alterar a estrutura do mesmo. Que design pattern é este?

Soluções