Programação Orientada por Objectos Tutorial 3: 31 In this tutorial we are going to develop a program that implements a simple game without GUI, though. Our main goal is to practice both modelling and implementation of inheritance. 0. As always start by reading thoroughly the problem description given in the appendix. Make sure you fully understand the problem. Should you have any doubt about it, do not hesitate to ask. 1. We must agree that this is a fairly simple game. We can think of many good possible solutions. However, we are taking this opportunity to exercise inheritance and the design pattern Template Method. 2. From the problem description we can identify three main classes: Jogo (Game in English), Jogador (Player), JogadorPoupado (SparedPlayer), and JogadorGastador (SpenderPlayer). 3. From the problem description, it is clear that Jogo(Game) has a set of Jogadores(Players). 4. It is also clear that the only difference between the two types of players is the way of playing, after the second turn. The JogadorPoupado (SparedPlayer) adds only 1 to the current count, and the JogadorGastador (SpenderPlayer) adds always 2. Remember that during the first turn all players do the same, i.e., they add 3 to the count. 5. This observation leads us to identify JogadorPoupado and JogadorGastador as subclasses of the class Jogador. Inheritance implies a is-a relationship between each subclass and its superclass and, JogadorPoupado(SparedPlayer) is-a Jogador (Player). The same apply to JogadorGastador(SpenderPlayer). Moreover, using inheritance, we can leave everything (i.e., both instance variables, and methods) common superclass/subclass in the superclass. Due to inheritance, the subclass can use them as its own. 6. This brief but most useful analysis can be documented in the following UML class diagram. At this time, we have included explicitly the Main class (where the client code is defined) in the diagram. We have also explicitly included the functional dependency relationship (denoted by the dashed arrow - - - >) meaning that class Main depends on class Jogo. http://w3.ualg.pt/~jvo/poo POO Lab Tutorial 3 - 1 Programação Orientada por Objectos Obviously, Main also depends on Jogador. However, this is not represented in the diagram. The reason is that it is not always a good idea to explicitly represent all functional dependencies between classes. If we did this, the diagram could become hard to read with all those relationships. Therefore, we will keep the representation of functional dependencies to a minimum, and only for those situations worth stressing. 7. We are now ready to start coding. Open Eclipse and create a new java project. 8. As always we will start by writing the client code, import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int nj = sc.nextInt(); Jogo trintaIum = new Jogo(); String nome, tipo; for(int i=0; i< nj; i++) { nome = sc.next(); tipo = sc.next(); if (tipo.compareToIgnoreCase("Poupado")==0) trintaIum.add(new JogadorPoupado(nome)); else if (tipo.compareToIgnoreCase("Gastador")==0) trintaIum.add(new JogadorGastador(nome)); else { System.err.print("Tipo de jogador desconhecido. "); System.exit(1); } } System.out.println(trintaIum.deBocaAeliminar()); } } 9. Since an object Jogo will be composed by, at least two objects from the hierarchy Jogador, the next class to code will be Jogador. abstract class Jogador{ final private String nome; private boolean primeiraVez = true; private static final int QPV=3; // Quantidade para a primeira vez; protected Jogador(String n) {nome =n;} public String toString() {return nome;} public final int joga() { if(primeiraVez) { primeiraVez = false; http://w3.ualg.pt/~jvo/poo POO Lab Tutorial 3 - 2 Programação Orientada por Objectos return QPV; } else return quantidade(); } abstract protected int quantidade(); public void setPrimeiraVez() {primeiraVez = true;} } 10. Notice that we have followed here the Template Method design pattern. We have prepared our class for inheritance. Specially, we have marked the class as abstract (the class will not have instances), we have identify joga() as the template method. It is marked final so it will not be redefined in any of the subclasses. As it is defined, this method uses the so-called Holywood principle “don’t call use, we call you”. Actually, the method calls function quantity() that is not defined in Jogador. This function is an abstract protected function, meaning that it should be redefined by Jogador subclasses. 11. With the restrictions above, the implementation of class JogadorPoupado is: class JogadorPoupado extends Jogador{ private static final int Quantidade=1; public JogadorPoupado(String s){ super(s); } protected int quantidade() {return JogadorPoupado.Quantidade;} } 12. Implement now the class JogadorGastador. At this point we may wonder whether this program architecture is really necessary. Believe me, it is a good opportunity for exercising inheritance and the Template Method in Java. 13. Based on what we have seen so far, we should be able to implement the class Jogo. 14. Test your program on appropriated test cases. 15. Submit your program to mooshak (http://www.deei.fct.ualg.pt/~mooshak) – problem D, get and an Accepted, and add 10 points to your lab score. http://w3.ualg.pt/~jvo/poo POO Lab Tutorial 3 - 3 Programação Orientada por Objectos Appendix: 31 // For the English version see below A expressão “Trinta e um” parece ter origem num jogo de cartas. Diz que o jogo era bem disputado o que invariavelmente dava lugar a desordem, zaragatas e embrulhadas. De resto, estes são os significados da expressão em frases como: “Arranjaste um belo trinta e um”.[1] Por outro lado, “31 de boca” significa uma declaração não confirmada por escrito, pelo que sem validade legal. Existe também um jogo de trinta-e-um de boca em que dois ou mais jogadores vão lançando números até que um deles chega ou ultrapassa os 31, sendo eliminado do jogo. Naturalmente que ganha o jogador que sobrevive. As regras do jogo são simples. Os jogadores jogam por ordem. Na sua vez de jogar, um jogador pode somar à contagem actual 1, 2 ou 3, sendo que só poderá somar 3 uma única vez. Quando um jogador é eliminado, a contagem volta a zero e o primeiro jogador a jogar é o jogador seguinte ao que foi eliminado. Na versão do jogo que nos interessa estudar existem apenas dois tipos de jogadores. Os Poupados e os Gastadores. Os Poupados somam invariavelmente 1 à contagem actual. Os Gastadores somam invariavelmente 2. Com receio de se esquecerem e serem eliminados do jogo, todos os jogadores somam 3 da primeira vez que têm oportunidade de jogar. Use os princípios e as técnicas de Programação Orientada por Objectos para escrever um programa em Java que simule a versão do jogo descrita acima. Input A primeira linha da entrada é um natural N indicando o número de jogadores. Seguem-se N linhas, cada uma das quais é constituída pelo nome, por um espaço e pelo tipo do jogador, que poderá ser Poupado ou Gastador. Output Uma string com o nome do jogador vencedor. Sample input 1 4 Almerindo Poupado Anacleto Gastador Anastacio Gastador Asdrubal Poupado Sample output 1 Asdrubal http://w3.ualg.pt/~jvo/poo POO Lab Tutorial 3 - 4 Programação Orientada por Objectos Appendix: 31 // Leia acima a versão Portuguesa The game “trinta-e-um de boca” is named after a idiomatic portugues expression. In this game, two or more players are counting up numbers. That player that reach 31 is eliminated. The player that survives will become the winner. The rules of the game are simple. Players play in turn. In his/her time of playing, a player can add to the current count 1, 2 or 3. However, 3 can be added only once. When a player is eliminated, the counter reset and the next to play is the player next to the eliminated one. In our version of the game, there are only two types of players: The Poupados and the Gastadores. The Poupados invariably add 1 to the current count. Gastores invariably add 2 to the current count. Both type of players add 3 to count in the first time they play. Use the principles and techniques of Object-Oriented Programming to write a program that runs the described version of the game. Input A primeira linha da entrada é um natural N indicando o número de jogadores. Seguem-se N linhas, cada uma das quais é constituída pelo nome, por um espaço e pelo tipo do jogador, que poderá ser Poupado ou Gastador. Output Uma string com o nome do jogador vencedor. Sample input 1 4 Almerindo Poupado Anacleto Gastador Anastacio Gastador Asdrubal Poupado Sample output 1 Asdrubal http://w3.ualg.pt/~jvo/poo POO Lab Tutorial 3 - 5