Exercicis
Exercici 7.1 (Firebase)
Farem una aplicació per a crear un xat entre el grup de classe. Per a poder compartir les dades entre tots, accedirem a una altra Base de Dades d'un altre usuari, tots utilitzarem el mateix:
- Compte de Google: ieselcaminas.ad@gmail.com
- Contrasenya: ad_ieselcaminas
En ell de moment només tenim la Base de Dades xat-ad, la referència de la qual és https://xat-ad.firebaseio.com/
PODEU FER L'APLICACIÓ EN ECLIPSE O EN ANDROID
Aplicació en Eclipse
Podeu utilitzar el "esquelet" que hi ha a continuació. En ell tenim:
- Una etiqueta per a indicar nom d'usuari
- Un JTextField per a introduir el nom de l'usuari. Aquestes dues coses han d'anar dalt de tot, en la mateixa línia.
- Un JTextArea, per a anar mostrant el chat
- Un altre JTextField per a introduir el nou text de conversa.
- Un botó d'Enviar. Aquestes dues coses han d'anar baix de tot, en la mateixa línia.
Haureu d'incorporar el fitxer json on està la configuració i la clau privada de la connexió. El fitxer s'anomena xat-ad-firebase-adminsdk-my2d0-8c69944b34.json, i el teniu com un recurs en l'aula virtual.
L'aplicació ha de guardar el missatge en el moment d'apretar el botó en la llista xat. Un missatge consta del nom de la persona que l'escriu (l'agafem del EditText de dalt), el moment en que es fa (l'agarrem de la data del sistema) i el contingut del missatge. Per a que siguen compatibles totes les aplicacions, han de tenir el mateix format, que serà:
- nom (string) contindrà el nom de la persona
- data (long) contindrà la data-hora del missatge
- contingut (string) el text del missatge
S'han de mostrar tots els elements de la llista xat, que seran tots els missatges i actualitzat al moment en que es cree un nou missatge (un nou elements de la llista) amb aquest format:
Usuari (data): missatge
A continuació teniu l'esquelet del programa que podeu utilitzar:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
public class Pantalla_Exercici7_1 extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
JLabel etiqueta = new JLabel("Missatges:");
JLabel et_usu = new JLabel("Nom d'usuari:");
JTextField usuari = new JTextField(15);
JTextArea area = new JTextArea();
JTextField missatge = new JTextField(15);
JButton enviar = new JButton("Enviar");
// en iniciar posem un contenidor per als elements anteriors
public void iniciar() throws IOException {
this.setBounds(100, 100, 450, 300);
this.setLayout(new BorderLayout());
// contenidor per als elements
JPanel panell1 = new JPanel(new FlowLayout());
panell1.add(et_usu);
panell1.add(usuari);
getContentPane().add(panell1, BorderLayout.NORTH);
JPanel panell2 = new JPanel(new BorderLayout());
panell2.add(etiqueta, BorderLayout.NORTH);
area.setForeground(Color.blue);
JScrollPane scroll = new JScrollPane(area);
panell2.add(scroll, BorderLayout.CENTER);
getContentPane().add(panell2, BorderLayout.CENTER);
JPanel panell3 = new JPanel(new FlowLayout());
panell3.add(missatge);
panell3.add(enviar);
getContentPane().add(panell3, BorderLayout.SOUTH);
setVisible(true);
enviar.addActionListener(this);
FileInputStream serviceAccount = new FileInputStream(
"xat-ad-firebase-adminsdk-my2d0-8c69944b34.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("https://xat-ad.firebaseio.com/").build();
FirebaseApp.initializeApp(options);
final DatabaseReference xat = FirebaseDatabase.getInstance().getReference("xat");
xat.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
// Sentències per a carregar les dades del xat al JTextArea area
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
// Sntències per a guardar el missatge
}
}
I ara el programa principal:
import java.io.IOException;
public class Exercici7_1 {
public static void main(String[] args) throws IOException {
final Pantalla_Exercici7_1 finestra = new Pantalla_Exercici7_1();
finestra.iniciar();
}
}
I aquest seria el resultat:

Aplicació en Android
- Creeu-vos una nova aplicació d'Android anomenada Xat_AD. Podeu utilitzar el mateix domini que en l'altre projecte.
- Incorporeu en ella:
- Una etiqueta per a indicar nom d'usuari
- Un EditText per a introduir el nom de l'usuari. Aquestes dues coses han d'anar dalt de tot, en la mateixa línia.
- Un TextView, per a anar mostrant el chat
- Un altre EditText per a introduir el nou text de conversa.
- Un botó d'Enviar. Aquestes dues coses han d'anar baix de tot, en la mateixa línia.
- Connecteu a la Base de Dades Firebase abans esmentada
L'aplicació ha de guardar el missatge en el moment d'apretar el botó en la llista xat. Un missatge consta del nom de la persona que l'escriu (l'agafem del EditText de dalt), el moment en que es fa (l'agarrem de la data del sistema) i el contingut del missatge. Per a que siguen compatibles totes les aplicacions, han de tenir el mateix format, que serà:
- nom (string) contindrà el nom de la persona
- data (long) contindrà la data-hora del missatge
- contingut (string) el text del missatge
S'han de mostrar tots els elements de la llista xat, que seran tots els missatges i actualitzat al moment en que es cree un nou missatge (un nou elements de la llista) amb aquest format:
Usuari (data): missatge
A continuació teniu un exemple de activity_main.xml que us podria servir:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.proves_alvar.xat_ad.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nom d'usuari:"
android:id="@+id/eti"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="@+id/textView" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/usuari"
android:layout_alignParentRight="true"
android:layout_toRightOf="@+id/eti"
android:layout_alignParentTop="true" />
<TextView
android:text=""
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@+id/usuari"
android:layout_above="@+id/missatge"
android:scrollbars="vertical"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/missatge"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@+id/boto"
android:layout_toStartOf="@+id/boto" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enviar"
android:id="@+id/boto"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_below="@+id/textView" />
</RelativeLayout>
Exercici 7.2 (Firebase) (voluntari)
Farem una aplicació en Android per a fer partides del Mastermind compartides. El joc consisteix a endevinar un número de 4 xifres no repetides. Quan es fa una tirada, l'aplicació contestarà quants xifres hi ha encertades i en el lloc corresponent, i quantes xifres encertades però fora del lloc.
Per exemple: Suposem que el número a endevinar és el 7481. A mida que anem fent tirades hem d'anar endevinant quin és el número:
- 1234 0 2 (que indica que no hi ha cap xifra al seu lloc, i que hi ha 2 encertades fora del lloc)
- 5678 0 2
- 1256 0 1
- 3487 2 1
- 7482 3 0
- 7481 4 0
Els usuaris connectats a l'aplicació (amb un nom d'usuari, millor si és breu, per exemple 3 caràcters, a l'estil de J01, J02, ...) han de poder fer jugades, i l'aplicació ha de mostrar primer el nom del jugador, la tirada i el resultat.
Per més simplicitat, només es guardarà una partida, però quan finalitze s'ha de poder començar una altra (esborrant les tirades de la partida anterior). Les dades que guardarem de la partida són:
Mastermind (serà la clau on ho guardarem tot)
- Número secret a endevinar: numSecret (string)
- Partida en marxa o bé ja finalitzada: finalitzada (boolean)
- Llista de tirades: tirades. De cadascuna:
- Jugador que l'ha feta: nom (string)
- Jugada feta: tirada (string)
- Encertades col·locades: colocades (String)
- Encertades no col·locades: desordenades (String)
Encara que possiblement podríem considerar colocades i desordenades com a números enters, per una altra banda les hem de mostrar per pantalla.
Tindrem els mateixos elements que en l'exercici anterior:
- Una etiqueta per a indicar nom de jugador
- Un EditText per a introduir el nom del jugador. Aquestes dues coses han d'anar dalt de tot, en la mateixa línia.
- Un TextView, per a anar mostrant les tirades de la partida
- Un altre EditText per a introduir la nova tirada.
- Un botó d'Enviar. Aquestes dues coses han d'anar baix de tot, en la mateixa línia.
- Per últim també tindrem un botó que inicialment està ocult per a començar una nova partida. Quan es visualitza tapa l'EditText de la nova tirada i el botó d'enviar, amb la qual cosa no es poden fer més intents
Inicialment s'ha de comprovar si la partida està en marxa. Si no ho està (o si no hi ha cap partida perquè és la primera vegada que s'executa):
- S'ha de generar un nou número secret i guardar-lo
- S'ha de marcar com a partida no finalitzada
Si ja està en marxa, senzillament s'han de visualitzar les tirades existents, i esperar per si es fa una tirada.
Quan es fa una tirada:
- S'ha de guardar el jugador, la tirada, el número de encertades col·locades i el número d'encertades no col·locades.
- Si s'ha encertat el número, s'ha de marcar com a finalitzada la partida, i s'ha de visualitzar el botó per a generar una nova partida
L'aplicació s'ha de dir Mastermind_AD. Les dades de connexió són les mateixes que l'exercici anterior:
- Compte de Google: ieselcaminas.ad@gmail.com
- Contrasenya: ad_ieselcaminas
Aquest seria el activity_main.xml amb els elements comentats abans:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.proves_alvar.mastermind_ad.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nom del jugador (preferiblement 3 caràcters):"
android:id="@+id/eti"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="@+id/textView" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/jugador"
android:layout_alignParentRight="true"
android:layout_toRightOf="@+id/eti"
android:layout_alignParentTop="true" />
<TextView
android:text=""
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="@+id/jugador"
android:layout_above="@+id/tirada"
android:scrollbars="vertical"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tirada"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@+id/boto"
android:layout_toStartOf="@+id/boto" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enviar"
android:id="@+id/boto"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_below="@+id/textView" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="NOVA PARTIDA"
android:id="@+id/botoNova"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_below="@+id/textView"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:visibility="invisible"/>
</RelativeLayout>
També us passe els mètodes genera(), que genera un número aleatori de 4 xifres no repetides, i comprova(String,String) que torna les xifres encertades col·locades i encertades no col·locades:
protected String genera(){
char[] n = new char[4];
n[0] = Integer.toString(((int) (Math.random() * 10))).charAt(0);
n[1] = Integer.toString(((int) (Math.random() * 10))).charAt(0);
while (n[1] == n[0])
n[1] = Integer.toString(((int) (Math.random() * 10))).charAt(0);
n[2] = Integer.toString(((int) (Math.random() * 10))).charAt(0);
while (n[2] == n[0] || n[2] == n[1])
n[2] = Integer.toString(((int) (Math.random() * 10))).charAt(0);
n[3] = Integer.toString(((int) (Math.random() * 10))).charAt(0);
while (n[3] == n[0] || n[3] == n[1] || n[3] == n[2])
n[3] = Integer.toString(((int) (Math.random() * 10))).charAt(0);
String generat= new String(n);
return generat;
}
protected int[] comprova(String num, String secret){
char[] n = secret.toCharArray();
int pos =0;
int nopos=0;
for (int i=0;i<4;i++)
for (int j=0; j<4; j++)
if (num.charAt(i)== n[j])
if (i==j) pos++;
else nopos++;
int[] solucio = new int[2];
solucio[0]=pos;
solucio[1]=nopos;
return solucio;
}
Exercici 7.3 (Redis)
En un nou paquet anomenat Exercicis dins del projecte Tema7_1, crea la classe ConsultarClaus.java, amb main, que permeta consultar totes les claus guardades en el nostre servidor Redis.
Ha de presentar totes les claus actuals en Redis i el seu tipus, però amb un número davant. Posteriorment ha de demanar un número per teclat, i presentar la clau i el valor corresponent al número introduït, fins introduir el 0. Observa que depenent del tipus de la clau s'haurà de fer d'una manera o una altra. En la imatge teniu un exemple de cada:
1.- clau_1 (string)
2.- mes2 (string)
3.- empleat_1 (hash)
4.- mes1 (string)
5.- saludar (string)
6.- empleat_2 (hash)
7.- mes6 (string)
8.- mes5 (string)
9.- mes4 (string)
10.- mes3 (string)
11.- colors (set)
12.- mes7 (string)
13.- llista1 (list)
14.- clau_Java (string)
15.- lista111 (list)
16.- colors1 (set)
17.- colors2 (set)
18.- colors3 (set)
19.- text (string)
20.- colors4 (set)
21.- clau_4 (string)
22.- clau_2 (string)
23.- puntuacions (zset)
24.- compt3 (string)
25.- compt2 (string)
26.- compt1 (string)
27.- quatre (string)
28.- pi (string)
Introdueix un número (0 per a eixir)
4
mes1: gener
Introdueix un número (0 per a eixir)
6
empleat_2
sou --> 1500.0
nom --> Berta
Introdueix un número (0 per a eixir)
13
llista1
primera
sisena
cinquena
Introdueix un número (0 per a eixir)
11
colors
roig
verd
blau
Introdueix un número (0 per a eixir)
23
puntuacions
Nom5 --> 2.75
Nom2 --> 3.5
Nom3 --> 5.0
Introdueix un número (0 per a eixir)
0
Exercici 7.4 (Redis)
Realitzar en el mateix paquet un altre programa, aquesta vegada gràfic, que ens diga el mateix, però d'una forma més atractiva.
- El programa principal s'ha de dir ConsultaClausGrafica.
- On estarà tot el programa s'ha de dir ConsultaClausGrafica_Pantalla.
- Contindrà un JList on han d'aparéixer totes les claus, millor si estan ordenades alfabèticament. Recordeu que el JList és un poc complicat, que es basa en un DefaultListModel, i és a aquest a qui heu d'afegir els elements.
- Al costat ha d'haver un JTextField que diga de quin tipus és quan se seleccione un element del JList
- I també un JTextArea amb el seu valor (siga del tipus que siga)
Aquest seria l'esquelet:
package Exercicis;
import java.awt.Color;
import java.awt.FlowLayout;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import redis.clients.jedis.Jedis;
public class ConsultaClausGrafica_Pantalla extends JFrame implements ListSelectionListener{
JLabel etTipClau= new JLabel("Tipus:");
JTextField tipClau= new JTextField(8);
JTextArea contClau = new JTextArea(8,15);
Jedis con = new Jedis("localhost");
DefaultListModel listModel = new DefaultListModel();
JList llClaus = new JList(listModel);
public void iniciar(){
this.getContentPane().setLayout(new FlowLayout());
llClaus.setForeground(Color.blue);
JScrollPane scroll = new JScrollPane(llClaus);
llClaus.setVisibleRowCount(20);
JScrollPane scroll2 = new JScrollPane(contClau);
this.add(scroll);
this.add(etTipClau);
this.add(tipClau);
this.add(scroll2);
this.setSize(600, 400);
this.setVisible(true);
inicialitzar();
llClaus.addListSelectionListener(this);
}
private void inicialitzar(){
}
@Override
public void valueChanged(ListSelectionEvent e) {
}
}
I aquest el seu aspecte

Exercici 7.5 (Redis) (voluntari)
Realitzar un programa anomenat JocEndevinaNumero.java (amb main), que faça el joc d'endevinar un número del 1 al 100. Cada vegada que el jugador pose un número el programa ha de dir si el número a endevinar és major o menor que l'introduït, fins que es trobe.
Posteriorment pregunta el nom i guarda'l amb la marca en un conjunt ordenat (Sorted Set) anomenat joc_marques, on utilitzarem com a valor el nom del jugador, i com a puntuació (score) que serveix per a ordenar, el temps. Com a complicació tindrem que en un conjunt ordenat (igual que en un conjunt) no es poden repetir els valors. Ha de ser de la següent manera:
- Medir el temps des de que comença la partida fins que es trobe el número. T'anirà bé la funció System.currentTimeMillis(), que dóna l'hora actual en milisegons. La diferència entre el primer moment i el segon, serà el número de milisegons que ha durat la partida.
- Primer guarda sense tenir en consideració que es puga repetir el nom del jugador.
- (Voluntari) Després millora'l, per a que si es posa un nom que ja existeix, li afegisca un número: nom, nom_1, nom_2, ...
- (Voluntari) Finalment, limita la llista de puntuacions a les 10 millors.
Exercici 7.6 (MongoDB)
Agafa l'estat actual de Bicicas de la següent adreça:
http://gestiona.bicicas.es/apps/apps.php
En l'annex del WebService tens la manera d'accedir a un WebService.
Estudia el format JSON, per a poder agafar bé la informació de cada estació.
- Fes un programa anomenat IntroduirBicicas (amb main) que introduesca en MongoDB cada estació com un document en una col·lecció anomenada bicicas.
- Fes un altre programa anomenat MostrarBicias que agafe tots els documents de la col·lecció bicicas de la Base de Dades de MongoDb, que són totes les estacions, i traga la seua informació amb aquest aspecte (només es mostren les 10 primeres)
00.- TALLER (0/1)
01.- UJI - FCHS (5/28)
02.- ESTACIóN DE FERROCARRIL Y AUTOBUSES (12/28)
03.- PLAZA DE PESCADERÃA (14/28)
04.- PASEO BUENAVISTA-GRAO (6/14)
05.- HOSPITAL GENERAL (9/18)
06.- PLAZA DE LA LIBERTAD (5/14)
07.- PLAZA TEODORO IZQUIERDO (0/14)
08.- PLAZA PRIMER MOLÃ (2/14)
09.- PATRONAT DESPORTS (4/14)
10.- PLAZA DOCTOR MARAñóN (7/14)
Exercici 7.7 (Firebase) Voluntari
Fer el joc del 3 en ratlla (TicTacToe) fet en PMDM, però per a 2 jugadors que juguen en terminals diferents. El primer que hauren de fer és connectar-se, i després començar a jugar. Ens guardarem en Firebase (dins de l'objecte TicTacToe) total la informació necessària:
- Ens guardarem l'estat de la partida en StateOfGame, que podrà tenir els valors Playing, Draw o Winner. Podria anar bé un nou estat anomenat Connecting. Inicialment podem considerar que l'estat és Draw.
- Ens guardarem la informació dels 2 jugadors: nom i símbol. Inicialment no tindran res. Quan el primer jugador es connecte s'inicialitzarà el jugador1 (per exemple amb els valors 1 X), i el valor seria Connecting. Quan es connecte el segon s'inicialitzarà el jugador2 (per exemple amb els valors 2 O). I l'estat passarà a ser Playing.
- En fer click a qualsevol botó, no s'ha de marcar encara amb el símbol del jugador (es farà després). S'ha de comprovar si és el torn del jugador (si no es el seu torn no es farà res). I en cas afirmatiu es guardarà la jugada, que constarà de: nom jugador, fila i columna. Observa com hauràs de poder identificar el botó (fila i columna) que s'ha apretat per poder guardar-lo. Les jugades s'aniran registrant com elements de l'array tirades (o moves)
- La jugada es marcarà en l'esdeveniment addChildEventListener() , tant si és pròpia com si és de l'altre jugador, utilitzant la fila, la columna i el nom per a marcar el botó correcte. Serà el moment de fer les comprovacions que ja teníeu en el joc.
- Quan finalitze la partida, a banda de marcar el guanyador o que no hi ha, s'ha de guardar el nou estat de la partida.