Activitats

Èxits crítics

L’objectiu d’aquesta activitat és, a partir d’un programa modular, saber triar on afegir noves funcionalitats de manera que se’n tregui màxim profit i mantenint els principis de modularitat inicials.

Es vol modificar el programa que ha servit com exemple als continguts d’aquest apartat afegint la regla següent. En mesurar el grau d’èxit d’una estratègia, hi ha d’haver una possibilitat que succeeixi un èxit crític. Quan això succeeix, en grau d’èxit es duplica. La probabilitat que això passi és igual al nivell de lluitador que duu a terme l’estratègia, en tant per cent. Per exemple, si és nivell 2, té una probabilitat de 2 sobre 100, un 2%.

Modifiqueu el programa per assolir això de manera que representi el mínim de modificacions al programa original. En fer-ho, mantingueu els principis de modularitat per a aquest programa, creant cada nou mètode que creieu necessari a la classe que li correspon.

Classe Monendes.java

  1. package joc.arena.regles;
  2.  
  3. import java.util.Random;
  4.  
  5. public class Monedes {
  6.  
  7. /** Resol el llançament d'un grup de monedes.
  8.   *
  9.   * @param numMonedes Nombre de monedes que s'han llençat.
  10.   * @param nivell Nivell del llançador de monedes.
  11.   * @return Nombre de cares obtingut.
  12.   */
  13. public int ferTirada(int numMonedes, int nivell) {
  14. Random rnd = new Random();
  15. int numCares = 0;
  16. for (int i =0; i < numMonedes; i++) {
  17. boolean tirada = rnd.nextBoolean();
  18. if (tirada) {
  19. numCares++;
  20. }
  21. }
  22. int critic = rnd.nextInt(99);
  23. if (critic < nivell) {
  24. numCares = numCares*2;
  25. }
  26. return numCares;
  27. }
  28.  
  29. }

També caldrà modificar les invocacions al mètode ferTirada que es fan des de la classe Lluitador.

Seleccionar un nom

L’objectiu d’aquesta activitat és, a partir d’un programa modular, saber triar on afegir noves funcionalitats de manera que se’n tregui màxim profit i mantenint els principis de modularitat inicials.

Modifiqueu el programa que ha servit com exemple als continguts d’aquest apartat perquè, a l’inici, el jugador pugui triar el seu nom d’entre tots els disponibles dins el joc, incloent els de tots els possibles adversaris, enlloc de dir-se sempre “Aventurer”. Com en el cas del combat, el jugador ha de saber que aquest existeix. A mesura que va fent partides, pot anar aprenent nous noms. En fer-ho, mantingueu els principis de modularitat per a aquest programa, creant cada nou mètode que creieu necessari a la classe que li correspon.

Classe Lluitador. Cal poder assignar un nou identificador associat a un nom.

  /** Assigna un nou identificador a un lluitador
   * 
   * @param lluitador Lluitador a modficar 
   * @param id Nou identficador
   */
  public void posarId(int[] lluitador, int id) {
    lluitador[ID]= id;    
  }

Classe Bestiari. Cal poder cercar noms i conèixer l’identificador associat.

  1. /** Diu l'identificador d'un nom concret
  2.   *
  3.   * @param nom Nom a cercar
  4.   * @return identificador, o -1 si no existeix el nom
  5.   */
  6. public int cercarNom(String nom) {
  7. for (int i = 0; i < noms.length; i++) {
  8. if (noms[i].equalsIgnoreCase(nom)) {
  9. return i;
  10. }
  11. }
  12. return -1;
  13. }

Classe EntradaTeclat. Cal gestionar la pregunta del nou nom.

  1. /** Es tria un nom pel jugador.
  2.   *
  3.   * @param ll Estatus del Jugador, a qui es canvia el nom
  4.   */
  5. public void triarNom(int[] ll) {
  6. System.out.print("Quin nom vols? ");
  7. Scanner lector = new Scanner(System.in);
  8. String resposta = lector.nextLine();
  9. Bestiari bestiari = new Bestiari();
  10. int id = bestiari.cercarNom(resposta);
  11. if (id == -1) {
  12. System.out.println("Aquest nom no existeix. Et diràs Aventurer.");
  13. } else {
  14. Lluitador lluitador = new Lluitador();
  15. lluitador.posarId(ll, id);
  16. }
  17. }

Classe JocArena. Ara es pregunta el nom un cop generat el jugador.

  1. public void inici() {
  2.  
  3. sortida.mostarBenvinguda();
  4. int[] jugador = bestiari.generarJugador();
  5.  
  6. entrada.triarNom(jugador);
  7.  
  8. //...
  9. }

Pocions de curació

L’objectiu d’aquesta activitat és, a partir d’un programa modular, saber triar on afegir noves funcionalitats de manera que se’n tregui màxim profit i mantenint els principis de modularitat inicials.

Ara mateix, a partir del programa que ha servit com a exemple als continguts d’aquest apartat, el joc pot ser una mica difícil, ja que el jugador no es guareix entre combats. Modifiqueu el programa de manera que el jugador tingui dues pocions de curació. El jugador ara disposa d’una nova estratègia de lluita consistent en usar-ne una. Quan ho fa, recupera tots els seus punts de vida, independentment de l’estratègia triada pel seu adversari durant aquella ronda. Si intenta usar-ne una quan ja no li queden, el programa dirà que no s’ha pogut dur a terme l’estratègia i rebrà dany si l’adversari tria atacar (en la resta d’estratègies, no passa res).

En fer-ho, mantingueu els principis de modularitat per a aquest programa, creant cada nou mètode que creieu necessari a la classe que li correspon.

Classe LLuitador. El nombre de pocions és un nou atribut.

  1. public final static int POCIONS = 9;
  2.  
  3. /** Intenta gastar una poció.
  4.   *
  5.   * @param lluitador Estatus del jugador
  6.   * @return Si quedaven pocions (true) o no (false)
  7.   */
  8. public boolean gastarPocio(int[] lluitador) {
  9. if (lluitador[POCIONS] > 0) {
  10. lluitador[POCIONS]--;
  11. lluitador[VIDA] = lluitador[VIDA_MAX];
  12. return true;
  13. }
  14. return false;
  15. }
  16.  
  17. /** diu quantes pocions queden
  18.   *
  19.   * @param lluitador Estatus del jugador
  20.   * @return Nombre de pocions
  21.   */
  22. public int llegirPocions(int[] lluitador) {
  23. return lluitador[POCIONS];
  24. }

Classe Combat. Ara hi ha una nova estratègia, i cal dir si s’ha pogut dur a terme.

  1. public static final int POCIO = 4;
  2.  
  3. public String estrategiaAText(int accio) {
  4. switch(accio) {
  5. case ATAC: return "ATAC";
  6. case DEFENSA: return "DEFENSA";
  7. case ENGANY: return "ENGANY";
  8. case MANIOBRA: return "MANIOBRA";
  9. case POCIO: return "USAR POCIÓ";
  10. }
  11. return "DESCONEGUDA";
  12. }
  13.  
  14. public boolean resoldreEstrategies(int[] jug, int accioJug, int[] adv, int accioAdv) {
  15.  
  16. //...
  17.  
  18. } else if ((accioJug == MANIOBRA)&&(accioAdv == MANIOBRA)) {
  19. //Jug i Adv: Penalitzat
  20. lluitador.penalitzar(adv, exitJug);
  21. lluitador.penalitzar(jug, exitAdv);
  22. } else {
  23. //Exercici pocions
  24. if (accioAdv == ATAC) {
  25. lluitador.danyar(jug, exitAdv);
  26. }
  27. if (accioJug == POCIO) {
  28. boolean ok = lluitador.gastarPocio(jug);
  29. return ok;
  30. }
  31. }
  32. return true;
  33.  
  34. }

Classe Bestiari. Cal donar un valor al nou atribut amb les pocions

  1. //Jugador: ID = 0
  2. private int[] jugador = {0, 1, 0, 10, 10, 3, 3, 3, 3, 2};
  3.  
  4. //Adversaris possibles al joc
  5. private int[][] adversaris = {
  6. {1, 1, 25, 8, 8, 3, 3, 3, 3, 0},
  7. {2, 1, 30, 10, 10, 4, 4, 2, 2, 0},
  8. {3, 2, 35, 12, 12, 4, 4, 3, 3, 0},
  9. {4, 2, 40, 14, 14, 3, 3, 4, 4, 0},
  10. {5, 3, 45, 15, 15, 3, 3, 5, 5, 0},
  11. {6, 3, 50, 16, 16, 5, 5, 2, 2, 0},
  12. {7, 4, 55, 15, 15, 4, 4, 4, 4, 0},
  13. {8, 4, 60, 18, 18, 3, 3, 5, 5, 0},
  14. {9, 5, 70, 22, 22, 4, 4, 6, 6, 0},
  15. {10, 5, 80, 30, 30, 8, 8, 2, 2, 0}
  16. };

Classe EntradaTeclat. Cal acceptar la nova estratègia

  1. public int preguntarEstrategia() {
  2. Scanner lector = new Scanner(System.in);
  3. System.out.println("Quina estratègia vols seguir aquesta ronda?");
  4. System.out.println("[A]tacar\t[D]efensar\t[E]ngany\t[M]aniobra\t[P]oció");
  5. System.out.println("--------");
  6. boolean preguntar = true;
  7. int accio = -1;
  8. while (preguntar) {
  9.  
  10. //...
  11.  
  12. } else if ("P".equalsIgnoreCase(resposta)) {
  13. //Activitat pocions
  14. accio = Combat.POCIO;
  15. preguntar = false;
  16. } else {
  17. System.out.print("Acció incorrecta...");
  18. }
  19. }
  20. return accio;
  21. }

Classe SortidaPantalla. Cal mostrar el nombre de pocions.

  1. public void mostrarVersus(int[] jugador, int[] adversari) {
  2. Lluitador lluitador = new Lluitador();
  3. System.out.print("JUGADOR: ");
  4. mostrarLluitador(jugador);
  5. System.out.println("POCIONS: " + lluitador.llegirPocions(jugador));
  6. System.out.println("VS");
  7. System.out.print("ADVERSARI: ");
  8. mostrarLluitador(adversari);
  9. }

Classe JocArena. Cal controlar si l’estratègia ha funcionat.

  1. public void combatre(int[] jugador, int[] adversari) {
  2.  
  3. //...
  4.  
  5. System.out.print("Has triat " + combat.estrategiaAText(accioJug));
  6. System.out.println(" i el teu enemic " + combat.estrategiaAText(accioAdv));
  7. boolean ok = combat.resoldreEstrategies(jugador, accioJug, adversari, accioAdv);
  8. if (ok == false) {
  9. System.out.println("No s'ha pogut dur a terme l'acció!");
  10. }
  11.  
  12. //...
  13.  
  14.  
  15. }

Les torres de Hanoi

L’objectiu d’aquesta activitat és estudiar un nou problema basat en una solució recursiva i veure com solucionar-lo.

Un dels problemes clàssics on una solució recursiva és molt més elegant i fàcil de plantejar que qualsevol altre mètode és l’anomenat “Torres de Hanoi”. En aquest es disposa de tres barres, dues de les quals estan buides i una amb un cert nombre de discos de diferent mida apilats, de manera que a sobre de cadascun d’ells sempre hi ha un disc de mida inferior. Mai pot haver-hi a sobre d’un disc un altre de mida superior. L’objectiu és passar tots els discos d’una barra a una altra, movent els discos d’un en un, pas a pas. A cada moviment, només es pot moure un disc que estigui en la posició superior d’alguna barra, i sempre de manera que es compleixi la condició descrita.

Cerqueu informació més detallada sobre aquest problema, estudieu atentament la seva solució recursiva i plantegeu un programa en Java que mostri la llista de moviments (“moure disc de torre X a torre Y”) que cal fer per resoldre el cas de 6 discos.

  1. package unitat5.apartat2.activitats;
  2.  
  3. public class Hanoi {
  4.  
  5. public static void main(String[] args) {
  6. Hanoi programa = new Hanoi();
  7. programa.inici();
  8. }
  9.  
  10. public void inici() {
  11. hanoi(6, 'A', 'B', 'C');
  12. }
  13.  
  14. /** Solució recursiva a les torres de Hanoi.
  15.   *
  16.   * @param numDisc Discos que cal moure des de l'origen
  17.   * @param origen Torre des d'on moure els discos
  18.   * @param desti Torre cap a on posar-los
  19.   * @param aux Torre auxiliar en el procés
  20.   */
  21. public void hanoi(int numDisc, char origen, char desti, char aux) {
  22. if (numDisc > 0) {
  23. hanoi (numDisc - 1, origen, aux, desti);
  24. System.out.println("moure disc de torre " + origen + " a torre " + desti);
  25. hanoi (numDisc - 1, aux, desti, origen);
  26. }
  27. }
  28. }

Les torres de Hanoi detallades

L’objectiu d’aquesta activitat és entendre quin és l’ordre com s’encadenen les invocacions als mètodes recursius.

Feu una nova versió del programa que soluciona les torres de Hanoi, però en aquest cas, en lloc d’enumerar els moviments, el que ha de mostrar és l’evolució de les torres al llarg de tot el procés. Per representar les torres, es poden usar cadenes de text, de manera que els dos primers caràcters diuen el nom de la torre (“A:”, “B:”, “C:”) i la resta son números que representen els discos.

Tingueu en compte que aquest problema és més complicat que la versió on només cal mostrar les passes, per la qual cosa aquí teniu una pista: us caldrà representar les torres usant variables globals.

Si es planteja per al cas de 4 discos, el programa podria mostrar:

A:6543 B: C:
A:654 B: C:3
A:65 B:4 C:3
A:65 B:43 C:
A:6 B:43 C:5
A:63 B:4 C:5
A:63 B: C:54
A:6 B: C:543
A: B:6 C:543
A: B:63 C:54
A:4 B:63 C:5
A:43 B:6 C:5
A:43 B:65 C:
A:4 B:65 C:3
A: B:654 C:3
A: B:6543 C:

  1. package unitat5.apartat2.activitats;
  2.  
  3. public class HanoiDetallat {
  4.  
  5. private String torreA = "A:6543";
  6. private String torreB = "B:";
  7. private String torreC = "C:";
  8.  
  9. public static void main(String[] args) {
  10. HanoiDetallat programa = new HanoiDetallat();
  11. programa.inici();
  12. }
  13.  
  14. public void inici() {
  15. hanoi(torreA.length() - 2, 'A', 'B', 'C');
  16. }
  17.  
  18. /** Solució recursiva a les torres de Hanoi.
  19.   *
  20.   * @param numDisc Discos que cal moure des de l'origen
  21.   * @param origen Torre des d'on moure els discos
  22.   * @param desti Torre cap a on posar-los
  23.   * @param aux Torre auxiliar en el procés
  24.   */
  25. public void hanoi(int numDisc, char origen, char desti, char aux) {
  26. if (numDisc > 0) {
  27. hanoi (numDisc - 1, origen, aux, desti);
  28. char d = treuDisc(origen);
  29. posaDisc(desti, d);
  30. System.out.println(torreA + " " + torreB + " " + torreC);
  31. hanoi (numDisc - 1, aux, desti, origen);
  32. }
  33. }
  34.  
  35. /** A partir del nom d'una torre, treu el darrer disc
  36.   *
  37.   * @param t Nom de la torre a modificar
  38.   * @return Disc extret
  39.   */
  40. public char treuDisc(char t) {
  41. char d = ' ';
  42. switch(t) {
  43. case 'A':
  44. d = torreA.charAt(torreA.length() - 1);
  45. torreA = torreA.substring(0, torreA.length() - 1);
  46. return d;
  47. case 'B':
  48. d = torreB.charAt(torreB.length() - 1);
  49. torreB = torreB.substring(0, torreB.length() - 1);
  50. return d;
  51. default:
  52. d = torreC.charAt(torreC.length() - 1);
  53. torreC = torreC.substring(0, torreC.length() - 1);
  54. return d;
  55.  
  56. }
  57.  
  58. }
  59.  
  60. /** A partir del nom d'una torre, hi posa un disc
  61.   *
  62.   * @param t Nom de la torre a modificar
  63.   * @param d Disc a posar
  64.   */
  65. public void posaDisc(char t, char d) {
  66. switch(t) {
  67. case 'A':
  68. torreA = torreA + d;
  69. break;
  70. case 'B':
  71. torreB = torreB + d;
  72. break;
  73. default:
  74. torreC = torreC + d;
  75. }
  76. }
  77.  
  78. }