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.
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:
- Obter média dos valores no array
- Obter mediana dos valores no array
- Obter moda dos valores no array
- Obter máximo dos valores no array
- Obter mínimo dos valores no_array
- Sair
O programa deve funcionar em ciclo, realizando os pedidos efetuados, terminando apenas quando o utilizador selecionar a opção 6.
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.
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)}");
}
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);
}
}
5 - Considera a seguinte declaração do método Next (classe Random, namespace System):
public virtual int Next(int minValue, int maxValue);
Indica:
- O nome do método.
- O tipo devolvido pelo método.
- Os argumentos aceites pelo método.
- A assinatura do método.
- Outras características indicadas na declaração.
- Se existe algum overload deste método na classe Random, e em caso afirmativo, mostrar as respetivas declaraçõ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.
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);
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);
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.
10 - No exercício anterior faria sentido a respetiva classe e o seu
único método serem static
? Porquê?
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.
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?
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:
- Qual a interface genérica comum a todas estas coleções? Que comportamento ficam as classes obrigadas a ter devido a implementarem essa interface?
- Explica sucintamente como estas coleções funcionam e dá exemplos onde cada uma seja especialmente útil.
- 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.
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:
- O tipo apresentado é de valor ou referência? Justifica a tua resposta.
- Identifica as variáveis de instância e explica o seu propósito.
- Identifica as propriedades auto-implementadas.
- Identifica as propriedades só de leitura.
- Identifica os construtores.
- Identifica os métodos de instância.
- Escreve a documentação XML apropriada para a classe e respetivos membros.
- Escreve um método
static
que recebe um iterável deGameMap
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
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:
- Quais são as vantagens desta
struct
ser imutável? - Podemos usar a sintaxe de inicialização de objetos com propriedades para
inicializar instâncias desta
struct
? Porquê?
16 - Quais são os requisitos para que uma classe possa ser instanciada usando a sintaxe de inicialização de coleções?
17 - Quais são os requisitos para que uma instância de uma classe possa ser
usada num foreach
como fornecedor de itens?
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:
- Faz as alterações necessárias à classe
Weapon
de modo a que quando invocarmos o métodoSort
(ou mais concretamente, o seu overload sem parâmetros) da classeList<T>
, as instâncias deWeapon
fiquem ordenadas porAttackPower
decrescente. Sugestão: a classeWeapon
tem de implementarIComparable<T>
. - Cria uma classe
Program
com um métodoMain()
para testar uma lista de várias instâncias deWeapon
, nomeadamente a sua ordenação porAttackPower
decrescente usando o métodoSort()
sem parâmetros. - O método
Sort
da classeList<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 interfaceIComparer<T>
. Cria uma classe deste tipo cujo critério de ordenação sejaDurability
crescente. - Adiciona ao método
Main()
da classeProgram
um teste à ordenação porDurability
crescente usando o métodoSort(IComparer<T>)
e a classe desenvolvida no ponto anterior.
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;
}
}
- O tipo
Spaceship
é de referência (classe) ou de valor (struct
ouenum
)? Porquê? - A classe está a usar métodos getter e setter. Não seria preferível usar uma propriedade? Justifica a tua resposta.
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:
- Considera que
monster
é uma instância deEnemy
. Escreve duas linhas de código, uma para imprimir no ecrã a propriedadeHealth
da instância, outra para imprimir a propriedadeNumberOfEnemies
da classe. - Porque razão faz sentido a propriedade
NumberOfEnemies
serstatic
? - De que parte do código pode ser alterado o valor da propriedade
NumberOfEnemies
?
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.
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:
- Implementa a classe
Sword
que estendeGameItem
, tendo adicionalmente como estado os camposlength
,typeOfMetal
econdition
. O primeiro pode ser representado com um número real, e os outros têm um tipo próprio,TypeOfMetal
eWeaponCondition
, respetivamente. O construtor deSword
aceita 5 parâmetros, que são usados para inicializar todos os campos da classe. No entanto, os campos herdados deGameItem
devem ser inicializados pelo respetivo construtor. - Cria as enumerações
TypeOfMetal
eWeaponCondition
com valores à tua escolha mas de modo a que façam sentido no contexto do problema. - Dá um exemplo em código de como podemos criar uma instância de
Sword
. - 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?
- Podemos instanciar diretamente
GameItem
? Porquê?
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).
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.
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?
26 - Considera as interfaces
IList<T>
e
IDictionary<TKey,TValue>
.
- Para cada uma das interfaces, dá um exemplo de uma coleção do C# que a implemente.
- Qual é ou quais são as funcionalidades que as coleções que implementam estas interfaces são obrigadas a ter?
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.
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:
- Existe algum campo
static
(de classe) na classeMonster
? - Adiciona o método iterável
CreateRandomMonsters()
à classeMonster
, que recebe um inteiro n indicando quantos monstros devem ser criados, e que devolve umIEnumerable<Monster>
de n monstros com campos inicializados aleatoriamente (dentro dos limites especificados nos tipos). - O método
CreateRandomMonsters()
deve serstatic
? Justifica a tua resposta. - Faz override do método
ToString()
na classeMonster
de modo a que o mesmo devolva uma string indicando, de forma bem formatada, as várias propriedades do monstro. Por exemplo, a propriedadeHealth
não deve ter mais de duas casas decimais. - Cria a classe
Program
com um métodoMain
para testares a criação de 20 monstros aleatórios com o métodoCreateRandomMonsters()
, imprimindo no ecrã a string devolvida pelo métodoToString()
para cada monstro.
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:
- 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.
- Interseção - Operação de interseção entre os dois conjuntos, ou seja, elementos simultaneamente presentes no conjunto 1 e no conjunto 2.
- 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.
- 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.
- 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.
- 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#.
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.
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; }
}
- Faz override dos métodos
GetHashCode()
eEquals()
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. - Testa a tua solução colocando vários objetos do tipo
Loot
num conjunto, repetindo propositadamente os campos de duas instâncias diferentes. - Se o tipo
Loot
fosse umastruct
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?
32 - Quais são os requisitos para que uma instância de uma classe possa ser
usada num foreach
como fornecedor de itens?
33 - Numa classe ou método genérico como podemos obrigar a que o tipo genérico tenha um construtor vazio?
34 - Numa classe ou método genérico como podemos obrigar a que o tipo genérico seja um tipo de referência?
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
)?
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:
- Como podemos diferenciar, no nosso código, entre o
Random
do C# e oRandom
do Unity? - 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?
37 - Considera a classe static
Input
do Unity.
Responde às seguintes questões:
- O que é necessário para que uma classe seja
static
? - Porque razão faz sentido a classe
Input
serstatic
? - O que é necessário fazer para usarmos os métodos e propriedades da classe
Input
diretamente no nosso código, por exemplo, escrevermosGetButton()
em vez deInput.GetButton()
? - Quais são os perigos de usar a abordagem indicada na pergunta anterior.
- Identifica mais duas classes
static
na API do Unity. Discute se faz sentido essas classes seremstatic
.
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();
}
}
- Cria uma classe
Program
com um métodoMain
para testar a classe apresentada. Mais concretamente, no métodoMain
deves: a) criar uma instância deBasketballTeam
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 classeBasketballTeam
ser iterável. - Supõe que o C# não tem a declaração
yield return
. Reescreve o métodoGetEnumerator
tendo em conta essa limitação. - Quais são as vantagens óbvias do uso de
yield return
relativamente à forma como reescreveste o código na alínea anterior?
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).
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.
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 novoTuple<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
.
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.
43 - Quais as vantagens e desvantagens do uso de out
e ref
na passagem de
parâmetros para métodos?
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.
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:
- É possível instanciar esta classe? Porquê?
- É possível estender esta classe? Porquê?
- Que métodos desta classe podem ser sobrepostos (overridden)? Porquê?
- Que métodos desta classe não podem ser sobrepostos (overridden)? Porquê?
- 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()
eAttackEnemies()
podem consistir apenas deConsole.WriteLines
. - Cria uma classe
Program
com um métodoMain()
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 deNPC
, percorrer a coleção, e invocar o métodoPlayTurn()
em cada uma delas. Repara que, além do construtor, só o métodoPlayTurn()
pode ser invocado a partir de outras classes. - Identifica a presença de polimorfismo na solução que apresentaste no ponto anterior.
- Desenha o diagrama UML da solução apresentada.
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?