Upload
independent
View
2
Download
0
Embed Size (px)
Citation preview
ALGORITMICA Y PROGRAMACION POR OBJETOS I
Nivel 6
Manejando Estructuras Contenedoras de 2 Dimensiones
y Persistencia
Marcela Hernández Hoyos
MotivaciónBrazoMecanico
Bodega
bodega
0 1 2 … maxX
ArrayList0 .. n
columnas
ArrayList0 .. n
filas
columnas
filas:Cubo
Bodega
Motivación
0 1 2 … maxX
BrazoMecanico
Bodega
bodegaArrayList0 .. n
columnas0 .. n
filas
ArrayList
columnas
filas:Cubo
Bodega
Qué vamos a aprender en este nivel:
Cómo definir, crear y manipular matrices (estructuras contenedoras de 2 dimensiones)
Patrones de recorrido de matrices
Esquema simple de persistencia (archivos)
El Visor de Imágenes -Funcionalidad
• Permite la visualización de imágenes en formato BMP
• Ofrece servicios de transformación de la imagen:– Transformar la imagen en su negativa– Aplicar un filtro– Rotar la imagen– Binarizar la imagen – …
El Visor de Imágenes – Mundo
IMAGEN: Único elemento del mundo Rojo
Verde
Azul
Se representa por medio de una MATRIZ
de 300x400
El Visor de Imágenes – Mundo
Imagen Color[300] [400]
bitmap
Único atributo de la clase Imagen llamado bitmap (nombre de la matriz)
int Rint Gint B
Clase nativa de Java
Así se indica en UML que se trata de una matriz (contenedora de 2 dimensiones)
Un objeto de la clase Imagen podría verse de la siguiente manera
: Imagen
Color bitmap =
: Color
R = 255G = 0B = 0
Cada elemento de la matriz apunta a un objeto de tipo Color
0 1 2 … 3990
1
…
299
Matriz = contenedora de 2 dimensiones de tamaño fijo
bitmap =
bitmap [0][0]
0 1 2 … 3990
1
…
299
bitmap [0][1]bitmap [0][399]
bitmap [1][0]
bitmap [299][399]
columnas
filas
bitmap [299][0]
•
bi
if
Matriz = contenedora de 2 dimensiones de tamaño fijo
bitmap =
• Cada posición de la matriz (casilla) se utiliza como una variable
bitmap[2][3] = new Color(0,0,0);
if ( bitmap[ i ][ j ] == bitmap[ 0 ][ 0 ] )…
0 1 2 … 3990
1
…
299
columnas
filas
Declaración de una matrizpublic class Imagen{
//Constantesfinal public static int ANCHO_MAXIMO = 400;final public static int ALTO_MAXIMO = 300;
//Atributosprivate Color [ ][ ] bitmap;
}
Se declaran constantes para fijar el tamaño de la matriz
Declaración de una matrizpublic class Imagen{
//Constantesfinal public static int ANCHO_MAXIMO = 400;final public static int ALTO_MAXIMO = 300;
//Atributosprivate Color [ ][ ] bitmap;
} bitmap es una matriz de dos dimensiones de tamaño fijo y cuyos elementos son TODOS de tipo Color
Declaración de una matrizpublic class Imagen{
//Constantesfinal public static int ANCHO_MAXIMO = 400;final public static int ALTO_MAXIMO = 300;
//Atributosprivate Color [ ][ ] bitmap;
}Color es una clase de
JAVA (paquete java.awt)
Declaración de una matrizpublic class Imagen{
//Constantesfinal public static int ANCHO_MAXIMO = 400;final public static int ALTO_MAXIMO = 300;
//Atributosprivate Color [ ][ ] bitmap;
}
También se puede escribir private Color bitmap [ ][ ]
Inicialización de una matrizpublic Imagen{
bitmap = new Color [ALTO_MAXIMO] [ANCHO_MAXIMO];}
• El espacio en memoria (una cajita por posición de la matriz) queda reservado.
• El valor de los elementos del arreglo es indefinido al comienzo (null).• Para consultar el número de filas de la matriz: length
bitmap.length• Para consultar el número de columnas de la matriz:
bitmap[0].length• Si se trata de acceder a una casilla con un par de índices no válidos
java.lang.ArrayIndexOutOfBoundsException
Acceso a los elementos de una matriz (ejemplo de recorrido total)
public void ImagenAzul ( ){
// Recorre la matriz inicializando las casillas con // objetos de tipo Color cuyo valor representa el azul
for ( int i = 0; i < ALTO_MAXIMO; i++ ){
for ( int j = 0; j < ANCHO_MAXIMO; j++ ){
bitmap[ i ][ j ] = new Color( 0, 0, 255);}
}}
Se necesitan 2 índices para acceder a una posición de la matriz:
• i: fila• j: columna
Entonces…
public void ImagenAzul ( ){
// Recorre la matriz inicializando las casillas con // objetos de tipo Color cuyo valor representa el azul
for ( int i = 0; i < ALTO_MAXIMO; i++ ){
for ( int j = 0; j < ANCHO_MAXIMO; j++ ){
bitmap[ i ][ j ] = new Color( 0, 0, 255);}
}}
Se necesitan 2 ciclos para recorrer la matriz:
• recorrido de TODAS las filas• para cada fila, recorrido de TODAS las columnas
Entonces…
Los índices van desde 0 hasta el número de elementos menos 1
public void ImagenAzul ( ){
// Recorre la matriz inicializando las casillas con // objetos de tipo Color cuyo valor representa el azul
for ( int i = 0; i < ALTO_MAXIMO; i++ ){
for ( int j = 0; j < ANCHO_MAXIMO; j++ ){
bitmap[ i ][ j ] = new Color( 0, 0, 255);}
}}
columnas
filas
Ahora con while…
public void ImagenAzul ( ){
// Recorre la matriz inicializando las casillas con // objetos de tipo Color cuyo valor representa el azul
int i = 0;while (i < ALTO_MAXIMO){
int j = 0;while ( j < ANCHO_MAXIMO ){
bitmap[ i ][ j ] = new Color( 0, 0, 255);j++;
}i++;
}}
columnas
filas
fila columna
Cómo comparar los elementos de una matriz (o arreglo) ?
• Si los elementos de una matriz son de tipo simple (enteros, reales, etc.) – Se comparan con el operador ==.
• Si los elementos NO son de tipo simple, sino que son objetos, en la matriz se guarda una referencia (apuntador) al objeto y NO el objeto mismo. En este caso, hay que compararlos con equals.
Un objeto de la clase Imagen podría verse de la siguiente manera
: Imagen
Color bitmap =
: Color
R = 255G = 0B = 0
Cada elemento de la matriz es UNA REFERENCIA(apunta) a un objeto de tipo Color
0 1 2 … 3990
1
…
299
Ejemplo de comparación
: Imagen
Color bitmap =
: Color
R = 255G = 0B = 0
0 1 20
1
: Color
R = 255G = 0B = 0
: Color
R = 255G = 0B = 0
: Color
R = 0G = 0B = 255
: Color
R = 0G = 0B = 255
: Color
R = 0G = 0B = 255
• Imagen de 2 x 3• Primera fila de
coloreada de rojo(255,0,0)
• Segunda fila coloreada de azul(0,0,255)
• Cada casilla tiene un objeto DIFERENTE que representa el color del pixel
Ejemplo de comparación
: Imagen
Color bitmap =
0 1 2
0
1
: Color
R = 255G = 0B = 0
: Color
R = 255G = 0B = 0
: Color
R = 255G = 0B = 0
: Color
R = 0G = 0B = 255
: Color
R = 0G = 0B = 255
: Color
R = 0G = 0B = 255
V Fbitmap[0][0] == bitmap[0][1]bitmap[0][0] .equals(bitmap[0][1])bitmap[0][0] .equals(bitmap[1][0])
Ejemplo de comparación
: Imagen
Color bitmap =
0 1 2
0
1
: Color
R = 255G = 0B = 0
: Color
R = 255G = 0B = 0
: Color
R = 255G = 0B = 0
: Color
R = 0G = 0B = 255
: Color
R = 0G = 0B = 255
: Color
R = 0G = 0B = 255
V Fbitmap[0][0] == bitmap[0][1] Xbitmap[0][0] .equals(bitmap[0][1]) Xbitmap[0][0] .equals(bitmap[1][0]) X
Ejemplo de asignación
: Imagen
Color bitmap =
0 1 2
0
1
: Color
R = 255G = 0B = 0
: Color
R = 255G = 0B = 0
: Color
R = 255G = 0B = 0
: Color
R = 0G = 0B = 255
: Color
R = 0G = 0B = 255
: Color
R = 0G = 0B = 255
Color temp = bitmap[0][0];
• Qué es temp?• Qué valor tiene?• Cómo se puede
visualizar?• Es un objeto o una
referencia?
Ejemplo de asignación
: Imagen
Color bitmap =
0 1 2
0
1
: Color
R = 255G = 0B = 0
Color temp = bitmap[0][0];
temp
• Qué es temp? R// Una variable• Qué valor tiene? R// el valor de bitmap[0][0]• Es un objeto o una referencia? R// Es una referencia al
mismo objeto que es referenciado por bitmap[0][0]
Ejemplo de asignación
: Imagen
Color bitmap =
0 1 2
0
1
: Color
R = 255G = 0B = 0
Color temp = bitmap[0][0];
temp
CONCLUSION:• TODAS las variables que tienen como valor un objeto,
son en realidad UNA REFERENCIA (apuntador) al objeto
Ejemplo de asignación
: Imagen
Color bitmap =
0 1 2
0
1
: Color
R = 255G = 0B = 0
Color temp = bitmap[0][0];
temp
En este caso:temp y bitmap[0][0] referencian el mismo objeto
Ejemplo de asignación
: Imagen
Color bitmap =
0 1 2
0
1
: Color
R = 255G = 0B = 0
Color temp = bitmap[0][0];
temp
Por lo tanto, las expresiones:temp == bitmap[0][0] es verdaderaTemp.equals(bitmap[0][0]) es verdadera también
Tarea No. 1 (for y while)• Recorrido total para contar el número de píxeles (puntos) de la imagen que
tienen el mismo color del dado como parámetro (usando equals de la clase Color !!!)
public int cuantosPixelColor( Color colorBuscado){
}
Patrón de recorrido total
• Se usa cuando se necesita recorrer TODA la matriz
• Ejemplos:– Contar cuántos puntos en la imagen son rojos– Cambiar el color de todos los puntos en la imagen
haciéndolos mas oscuros– Cambiar cada color de la imagen por su negativo– Contar cuántos puntos en la imagen tienen una
componente roja distinta de cero
Patrón de recorrido total
• Se usan DOS ciclos:– Un primer ciclo recorre las filas– Por cada fila, un segundo ciclo recorre sus
columnas
Patrón de recorrido totalIndice del primer ciclo
empieza en CERO
for ( int i = 0; i < NUM_FILAS; i++){
for ( int j = 0; j < NUM_COLUMNAS; j++){<cuerpo del ciclo>
}}
Primer ciclo: recorrido de filas
Patrón de recorrido totalCondición para continuar: índice menor que el número de filas
for ( int i = 0; i < NUM_FILAS; i++){
for ( int j = 0; j < NUM_COLUMNAS; j++){<cuerpo del ciclo>
}}
Primer ciclo: recorrido de filas
Patrón de recorrido totalAvance: incremento
en 1 del índice
for ( int i = 0; i < NUM_FILAS; i++){
for ( int j = 0; j < NUM_COLUMNAS; j++){<cuerpo del ciclo>
}}
Primer ciclo: recorrido de filas
Patrón de recorrido total
for ( int i = 0; i < NUM_FILAS; i++){
for ( int j = 0; j < NUM_COLUMNAS; j++){<cuerpo del ciclo>
}}
Indice del primer ciclo empieza en CERO
Segundo ciclo: recorrido de columnas
Patrón de recorrido total
for ( int i = 0; i < NUM_FILAS; i++){
for ( int j = 0; j < NUM_COLUMNAS; j++){<cuerpo del ciclo>
}}
Condición para continuar: índice menor que el número de columnas
Segundo ciclo: recorrido de columnas
Patrón de recorrido totalAvance: incremento
en 1 del índice
for ( int i = 0; i < NUM_FILAS; i++){
for ( int j = 0; j < NUM_COLUMNAS; j++){<cuerpo del ciclo>
}}
Segundo ciclo: recorrido de columnas
Ejemplo: Modificación de la matriz
for ( int i = 0; i < ALTO_MAXIMO; i++){
for ( int j = 0; j < ANCHO_MAXIMO; j++){
bitmap[ i ][ j ] = bitmap[ i ][ j ].darker( );}
}
Oscurece TODA la imagen con el método darker de la clase Color
Ejemplo: Cálculo sobre la matriz (uso de acumulado)
public int rojosCero( ){int cuantosRojoCero = 0;for ( int i = 0; i < ALTO_MAXIMO; i++){
for ( int j = 0; j < ANCHO_MAXIMO; j++){Color c = bitmap[ i ][ j ];if ( c.getRed() == 0 ){
cuantosRojoCero++;}
}}return cuantosRojoCero;
}
Cuenta cuántos puntos tienen el componente rojo igual a cero.
Tarea No. 2• Recorrido total para modificar los puntos de la matriz,
convirtiéndolos en sus negativos. El negativo se calcula restándole 255 a cada componente RGB del color y tomando el valor absoluto del resultado.
public void negativoImagen( ){
}
Tarea No. 2• Recorrido total para calcular la tendencia de color de la imagen. Esto se
calcula de la siguiente manera: un pixel tiene un color de tendencia roja, si su índice es mayor que los otros dos. Lo mismo sucede con los demás colores. Este método retorna 0 si la imagen no tiene ninguna tendencia, 1 si la tendencia es roja, 2 si la tendencia es verde y 3 si la tendencia es azul.
public int calcularTendencia( ){
}
Patrón de recorrido parcial• Se usa cuando se NO necesita recorrer TODA
la matriz• Existe una condición que debemos verificar en
cada iteración para saber si debemos detener los ciclos o volver a repetirlos
• Ejemplos:– Saber si hay al menos un punto negro (0,0,0) en la
imagen– …– …– …
Patrón de recorrido parcial (1)
boolean termino = false;for ( int i = 0; i < NUM_FILAS && !termino ; i++){
for ( int j = 0; j < NUM_COLUMNAS && !termino; j++){<cuerpo del ciclo>
if ( <problema terminado> )termino = true;
}}
Uso de un mismo centinela en los dos ciclos
La variable termino puede ser remplazada por cualquier condición que indique el punto en el que el problema ya ha sido resuelto y se deben interrumpir los dos ciclos
Ejemplo (1)
public boolean hayPuntoNegro( ){boolean termino = false;for ( int i = 0; i < ALTO_MAXIMO && !termino ; i++){
for ( int j = 0; j < ANCHO_MAXIMO && !termino; j++){
if ( bitmap[ i ][ j ].equals(Color.BLACK) ){
termino = true;}
}}return termino;
}
Dice (verdadero o falso) si hay al menos un punto negro en la imagen.
Patrón de recorrido parcial (2)
boolean termino1 = false;for ( int i = 0; i < NUM_FILAS && !termino1 ; i++){
boolean termino2 = false;for ( int j = 0; j < NUM_COLUMNAS && !termino2; j++){<cuerpo del ciclo>if ( <problema interno terminado> )termino2 = true;
}if ( <problema externo terminado> )termino1 = true;
}
Uso de un centinela diferente para cada ciclo
• Con termino1 se maneja el recorrido parcial del ciclo externo
• Con termino2 se maneja el ciclo interno
• termino1 y termino2 pueden ser remplazadas por condiciones
Ejemplo (2)public boolean hayMuchasFilasConPixelNegro( ){boolean termino1 = false;int numFilas = 0;for ( int i = 0; i < ALTO_MAXIMO && !termino1 ; i++){
boolean termino2 = false;for ( int j = 0; j < ANCHO_MAXIMO && !termino2; j++){
if ( bitmap[ i ][ j ].equals(Color.BLACK) ){
numFilas++;termino2 = true;
}}if ( numFilas > 50 )termino1 = true;
}return termino1;
}
Dice (verdadero o falso) si hay mas de 50 filas en la imagen con un punto negro.
Tarea No. 3• Filtrar una imagen con un filtro promedio. En el proceso de adquisición de
una imagen, ésta puede quedar con una serie de errores los cuales hacen que se vea de mala calidad. Para corregir estos errores existe un algoritmo de filtrado, el cual está basado en el cálculo de un nuevo valor para cada píxel de la imagen. Este valor es calculado como el promedio de los 8 vecinos del píxel en la imagen original, sobre cada uno de los componentes RGB. En este proceso no se incluyen los bordes de la imagen, puesto que no tienen los 8 vecinos necesarios. Este método de la clase Imagen debe retornar una matriz con una copia de la imagen filtrada.
Tarea No. 3• Este método de la clase Imagen debe retornar una matriz con una copia de
la imagen filtrada. public Color [ ] [ ] imagenFiltrada( ){
}
Tarea No. 3• Escriba un método de la clase Imagen que modifique la matriz de píxeles
de la siguiente manera: si la suma de los tres componentes RGB de un píxel es menor que 100, lo debe remplazar por el color blanco (0,0,0). En caso contrario lo remplaza por el color negro (255,255,255).
public void binarizar( ){
}
Tarea No. 3• Escriba un método de la clase Imagen que sea capaz de rotarla 90
grados a la derecha.public void rotar90AlaDerecha( ){
}
Otros algoritmos de recorrido
• Son adaptaciones de los patrones de recorrido total y parcial.
• Ejemplos:– Recorrer sólo una fila– Recorrer sólo una columna– Recorrer sólo la diagonal
Ejemplo: Recorrer sólo una filapublic int contarVerdes( int numFila){int numVerdes = 0;for ( int j = 0; j < ANCHO_MAXIMO; j++){
if ( bitmap[ numFila ][ j ].getGreen( ) == 255 )numVerdes++;
}return numVerdes;
}
Cuenta el numero de píxeles de la fila “numFila” cuyo componente verde es el máximo posible (255).
Ejemplo: Recorrer sólo una columna
public int darSumaAzulColumna( int numColumna){int acumAzul = 0;for ( int i = 0; i < ALTO_MAXIMO; i++){
acumAzul += bitmap[ i ][ numColumna ].getBlue( );}return acumAzul;
}
Calcula la suma del valor azul de todos los píxeles de la columna “numColumna”.
Ejemplo: Recorrer sólo la diagonal
public boolean negroEnDiagonal( ){for ( int i = 0; i < ALTO_MAXIMO && i < ANCHO_MAXIMO; i++){
if ( bitmap[ i ][ i ].equals( Color.BLACK ) )return true;
}return false;
} Indica (true / false) si hay un pixel negro sobre la diagonal de la imagen.
El Campeonato de Fútbol
• Funcionalidad – Requerimientos funcionales
• Interfaz usuario• Mundo del problema• Persistencia
El Campeonato de Fútbol -Funcionalidad
• Manejo de los resultados de los partidos de un campeonato de fútbol.
• En el campeonato:– Hay varios equipos.– Cada equipo puede jugar contra cada uno de los otros
equipos una sola vez.• Información de los equipos está en un archivo.• La aplicación debe permitir:
– Registrar el resultado de los partidos– Mostrar la tabla de goles– Mostrar la tabla de posiciones
El Campeonato de Fútbol –Requerimientos Funcionales
R1 Registrar el resultado de un partidoR2 Leer la información del campeonato de un archivo de entradaR3 Presentar la tabla de golesR4 Presentar la tabla de posiciones
R1
R2
R3 R4
El Campeonato de Fútbol –Requerimientos Funcionales
• RF1: Registrar el resultado de un partido
• Entradas:– Equipo 1– Equipo 2– Goles del equipo 1– Goles del equipo 2
El Campeonato de Fútbol –Requerimientos Funcionales
• RF2: Leer la información del campeonato de un archivo de entrada
• Entradas:– Nombre del
archivo
El Campeonato de Fútbol –Requerimientos Funcionales
• RF3: Presentar la tabla de goles
• Entradas: Ninguna
El Campeonato de Fútbol –Requerimientos Funcionales
• RF4: Presentar la tabla de posiciones
• Entradas: Ninguna
El Campeonato de Fútbol –Mundo
Campeonato Equipo0 .. maxEquipos
tablaGoles
int maxEquipos String nombre
Gol
equipos
maxEquipos X maxEquipos
El Campeonato de Fútbol –Mundo
Campeonato Equipo0 .. maxEquipos
tablaGoles
int maxEquipos String nombre
Gol
maxEquipos X maxEquipos
equipos
Campeonato
int tablaGoles =En implementación real, NO hay clase Gol. tablaGoles es una matriz de enteros
La clase Campeonatopublic class Campeonato{
//Constantesfinal public static int SIN_JUGAR = -1;final public static int INVALIDO = -2;
//Atributosprivate int maxEquipos;private int [ ] [ ] tablaGoles;private Equipo[ ] equipos;
}
La clase Campeonatopublic class Campeonato{
//Constantesfinal public static int SIN_JUGAR = -1;final public static int INVALIDO = -2;
//Atributosprivate int maxEquipos;private int [ ] [ ] tablaGoles;private Equipo[ ] equipos;
}
Los equipos son modelados como un arreglo de tamaño fijo
La clase Campeonatopublic class Campeonato{
//Constantesfinal public static int SIN_JUGAR = -1;final public static int INVALIDO = -2;
//Atributosprivate int maxEquipos;private int [ ] [ ] tablaGoles;private Equipo[ ] equipos;
}
La información de los equipos se lee de un archivo: NO ES CONSTANTE, se modela con un atributo
La clase Campeonatopublic class Campeonato{
//Constantesfinal public static int SIN_JUGAR = -1;final public static int INVALIDO = -2;
//Atributosprivate int maxEquipos;private int [ ] [ ] tablaGoles;private Equipo[ ] equipos;
}
La tabla de goles es una matriz CUADRADA (número de filas = número de columnas = número de equipos)
La tabla de golesint tablaGoles =
equipo1
equipo2
tablaGoles [ equipo1 ] [ equipo2 ] = número de goles que el equipo1 hizo al equipo2
1 2
La tabla de golesint tablaGoles =
equipo2
equipo1
tablaGoles [ equipo2 ] [ equipo1 ] = número de goles que el equipo2 hizo al equipo1
2 1
La tabla de golesint tablaGoles =
equipo1
equipo1
tablaGoles [ equipo1 ] [ equipo1 ] = INVALIDO (constante = -2)
Un equipo NO puede jugar contra el mismo1 1
La clase Campeonatopublic class Campeonato{
//Constantesfinal public static int SIN_JUGAR = -1;final public static int INVALIDO = -2;
//Atributosprivate int maxEquipos;private int [ ] [ ] tablaGoles;private Equipo[ ] equipos;
}
Indica que el partido es INVALIDO porque un equipo NO puede jugar contra si mismo
La tabla de golesint tablaGoles =
INVALIDO
INVALIDO
INVALIDO
INVALIDO
La diagonal de la matriz tiene SIEMPRE el valor INVALIDO (= -2)
La tabla de golesint tablaGoles =
?equipo1
equipo2
tablaGoles [ equipo1 ] [ equipo2 ] = SIN_JUGAR ( constante = -1 )
Si un partido NO se ha jugado, NO se conoce el
resultado, este es SIN_JUGAR
La clase Campeonatopublic class Campeonato{
//Constantesfinal public static int SIN_JUGAR = -1;final public static int INVALIDO = -2;
//Atributosprivate int maxEquipos;private int [ ] [ ] tablaGoles;private Equipo[ ] equipos;
}
Indica que el partido NO se ha jugado
Responsabilidades de la clase Campeonato
• La clase Campeonato es la DUEÑA de los equipos y los goles, por lo tanto es la responsable de:
– Dar la información sobre los equipos– Dar la información sobre la tabla de goles– Dar la información sobre la tabla de posiciones
• Además es responsable de:– Registrar el resultado de un partido– Cargar la información del campeonato (de un archivo) y
llenar con ella el arreglo de equipos
Registrar el Resultado de un Partido/**
* Registra el resultado de un partido <br>* <b>pre: </b> Los equipos que participan en el campeonato ya * fueron inicializados. * <b>post: </b>Se actualizó la tabla de goles con el resultado indicado* * @param eq1 - Es el número del equipo 1 (Indice dentro de la matriz)* @param eq2 - Es el número del equipo 2 (Indice dentro de la matriz)* @param gol1 - Es el número de goles marcados por el equipo 1* @param gol2 - Es el número de goles marcados por el equipo 2* @throws Exception Se lanza excepción si: * los equipos no son válidos, * el número de goles es inválido * el partido ya se ha jugado antes*/
Registrar el Resultado de un Partidopublic void registrarResultado(int eq1, int eq2, int gol1, int gol2) throws Exception{
if ( eq1 < 0 || eq1 >= maxEquipos || eq2 < 0 || eq2 >= maxEquipos ) {
throw new Exception("Equipos incorrectos");}if ( eq1 == eq2 ) {
throw new Exception(“Son el mismo equipo");}if ( gol1 < 0 || gol2 < 0 ) {
throw new Exception(“Número de goles inválido");}if ( tablaGoles[ eq1 ][ eq2 ] != SIN_JUGAR ||
tablaGoles[ eq2 ][ eq1 ] != SIN_JUGAR ) {
throw new Exception(“Partido ya jugado antes");
} …
Verificación de los datos de entrada
Registrar el Resultado de un Partidopublic void registrarResultado(int eq1, int eq2, int gol1, int gol2) throws Exception{
…tablaGoles[ eq1 ][ eq2 ] = gol1;tablaGoles[ eq2 ][ eq1 ] = gol2;
}
Asignación de los goles en las posiciones correctas de la matriz
gol1
gol2
eq1
eq2
Responsabilidades de la clase Campeonato
• La clase Campeonato es la DUEÑA de los equipos y los goles, por lo tanto es la responsable de:
– Dar la información sobre los equipos– Dar la información sobre la tabla de goles– Dar la información sobre la tabla de posiciones
• Además es responsable de:– Registrar el resultado de un partido– Cargar la información del campeonato (de un archivo) y
llenar con ella el arreglo de equipos
Construir la tabla de posiciones
1 022
10 2 3 4
A.C. Milan 0tablaGoles[ 0 ] [ 1 ] < tablaGoles[ 1 ] [ 0 ] Inter 1
Juventus 2
Roma 3A.C. Milan ( índice 0 ) jugó contra el
Inter ( índice 1 ) y perdió 1 a 2Lazio 4
SIN_JUGAR
INVALIDO
Construir la tabla de posiciones
1 022
10 2 3 4
A.C. Milan 0
Inter 1 tablaGoles[ 0 ] [ 2 ] < tablaGoles[ 2 ] [ 0 ] Juventus 2
Roma 3A.C. Milan ( índice 0 ) jugó contra el Juventus ( índice 2 ) y perdió 0 a 2
Lazio 4
SIN_JUGAR
INVALIDO
Construir la tabla de posiciones
• Para cada equipo, se debe calcular:1. Partidos jugados (PJ)2. Partidos ganados (PG)3. Partidos empatados (PE)4. Partidos perdidos (PP)5. Goles a favor (GF)6. Goles en contra (GC)7. Puntos (Pts) SOLUCIÓN…
Tarea No. 4• Escriba un método de la clase Campeonato que calcule el número
total de partidos ganados por el equipo que se recibe como parámetro.
public int partidosGanados( int equipo ){
}
Tarea No. 4• Escriba un método de la clase Campeonato que calcule el número
total de partidos empatados por el equipo que se recibe como parámetro.
public int partidosEmpatados( int equipo ){
}
Tarea No. 4• Escriba un método de la clase Campeonato que calcule el número
total de partidos jugados por el equipo que se recibe como parámetro.
public int partidosJugados( int equipo ){
}
Tarea No. 4• Escriba un método de la clase Campeonato que calcule el número
total de goles marcados por el equipo que se recibe como parámetro.
public int golesAFavor( int equipo ){
}
Tarea No. 4• Escriba un método de la clase Campeonato que calcule el número total de
puntos del equipo que se recibe como parámetro. Tenga en cuenta que un equipo recibe 3 puntos por cada partido ganado y un punto por cada partido empatado
public int calcularTotalPuntos( int equipo ){
}
Tarea No. 5• Escriba un método de la clase Campeonato que retorne el índice del equipo
que va ganando el campeonato. Si hay dos equipos con el mismo número de puntos, gana aquel cuya diferencia de goles (goles anotados menos goles recibidos) sea mayor.
public int calcularGanador( ){
}
Tarea No. 5• Escriba un método de la clase Campeonato que calcule el número
de partidos que faltan por jugar en el campeonato.public int calcularPorJugar( ){
}
Tarea No. 5• Escriba un método de la clase Campeonato que calcule el mayor
número de goles marcados en un partido del campeonato (sumando los goles de los dos equipos).
public int calcularTotalGoles( ){
}
Tarea No. 5• Escriba un método de la clase Campeonato que calcule el número
de partidos del campeonato cuyo marcador fue cero a cero.public int calcularTotalCeroACero( ){
}
Responsabilidades de la clase Campeonato
• La clase Campeonato es la DUEÑA de los equipos y los goles, por lo tanto es la responsable de:
– Dar la información sobre los equipos– Dar la información sobre la tabla de goles– Dar la información sobre la tabla de posiciones
• Además es responsable de:– Registrar el resultado de un partido– Cargar la información del campeonato (de un archivo) y
llenar con ella el arreglo de equipos
PERSISTENCIA … a 1/2
Persistencia es …• Guardar los datos resultado de un programa en un
archivo para hacerlos persistentes cuando la aplicación termine.
• Es tema de APO2 !!!• En APO1 … introducción a persistencia:
– Leer y cargar los datos de un archivo para configurar el estado inicial de los elementos del mundo
– Ejemplos:• Cargar las preguntas y respuestas del examen.• Abrir una imagen.• Ahora … leer la información de los equipos del campeonato
para configurar el estado inicial del mundo.
Qué es un archivo ?• Una entidad que contiene información y que es
almacenada en la memoria secundaria del computador (disco duro, CD, unidad USB, diskette …)
• Tiene un nombre y una extensión• El nombre tiene una ruta (camino o path en
inglés) y el nombre corto propiamente dicho.
c:/apoo/uniandes/cupi2/empleado/mundo/Empleado.java
Qué es un archivo ?
c:/apoo/uniandes/cupi2/empleado/mundo/Empleado.java
• Ruta = estructura de directorios dentro de los cuales se encuentra el archivo, empezando por la raíz del disco
• “/”: separador de nombres de archivos• Extensión: indica el tipo del archivo (doc para word,
xls para excel, txt para texto, java para java, …)
Ejemplo de archivos –Imagen BMP (bitmap)
Es un archivo especial (no es texto plano). Solo se puede leer con una aplicación especializada (paint, photo shop, paint shop pro, visor de imágenes de APO1 !!!, …)
Lectura de Archivos: desde la selección del archivo hasta
la inicialización del estado del mundo de la aplicación
Selección del archivo
El usuario genera un evento oprimiendo el botón. Se dispara el método cargarEquipos de la ventana principal (clase InterfazCampeonato)
En el método cargarEquipos …
public class InterfazCampeonato extends JFrame{ …
public void cargarEquipos( ){
JFileChooser fc = new JFileChooser( "./data" );fc.setDialogTitle( "Abrir archivo de campeonato" );int resultado = fc.showOpenDialog( this );
}}
Caja de diálogo para escoger el archivo con la clase JFileChooser (JAVA)
Se muestra al usuario la caja de diálogo para seleccionar el archivo
En el método cargarEquipos …
public class InterfazCampeonato extends JFrame{ …
public void cargarEquipos( ){
File archivoCampeonato = null;
JFileChooser fc = new JFileChooser( "./data" );fc.setDialogTitle( "Abrir archivo de campeonato" );int resultado = fc.showOpenDialog( this );
if( resultado == JFileChooser.APPROVE_OPTION ){
archivo = fc.getSelectedFile( );}
else{
return;}
}}
Se obtiene el archivo seleccionado, que es un objeto de la clase File (de JAVA)
Se muestra al usuario la caja de diálogo para seleccionar el archivo
En el método cargarEquipos …
public class InterfazCampeonato extends JFrame{ …
public void cargarEquipos( ){
File archivoCampeonato = null;
JFileChooser fc = new JFileChooser( "./data" );fc.setDialogTitle( "Abrir archivo de campeonato" );int resultado = fc.showOpenDialog( this );
if( resultado == JFileChooser.APPROVE_OPTION ){
archivoCampeonato = fc.getSelectedFile( );campeonato = new Campeonato( archivoCampeonato );
}}
}Se llama al método constructor de la clase Campeonato, que recibe como parámetro, el archivo
Se crea el objeto campeonato
En el método constructor de la clase Campeonato …
public class Campeonato{ …
public Campeonato( File arch ){
Properties datos = cargarInfoCampeonato( arch );inicializarEquipos( datos );inicializarTablaGoles( );
}}
Se llama al método cargarInfoCampeonato de la clase Campeonato, que recibe como parámetro, el archivo
Se carga la información del campeonato, a partir del archivo
En el método cargarInfoCampeonato de la clase Campeonato …
public class Campeonato{ …
private Properties cargarInfoCampeonato( File arch ){
Properties datos = new Properties( );FileInputStream in = new FileInputStream( arch );datos.load( in );in.close( );return datos;
}}
Carga la información del archivo en un objeto de tipo Properties (JAVA) y retorna este objeto
En el método cargarInfoCampeonato de la clase Campeonato …
public class Campeonato{ …
private Properties cargarInfoCampeonato( File arch ){
Properties datos = new Properties( );FileInputStream in = new FileInputStream( arch );datos.load( in );in.close( );return datos;
}}
Crea el objeto de tipo Properties
En el método cargarInfoCampeonato de la clase Campeonato …
public class Campeonato{ …
private Properties cargarInfoCampeonato( File arch ){
Properties datos = new Properties( );FileInputStream in = new FileInputStream( arch );datos.load( in );in.close( );return datos;
}}
Crea un objeto de tipo FileInputStream(clase de JAVA que permite cargar archivos) ≅ Canal por donde se transmiten los datos desde el disco duro hasta el programa
En el método cargarInfoCampeonato de la clase Campeonato …
public class Campeonato{ …
private Properties cargarInfoCampeonato( File arch ){
Properties datos = new Properties( );FileInputStream in = new FileInputStream( arch );datos.load( in );in.close( );return datos;
}}
Carga el archivo mediante el método load
En el método cargarInfoCampeonato de la clase Campeonato …
public class Campeonato{ …
private Properties cargarInfoCampeonato( File arch ){
Properties datos = new Properties( );FileInputStream in = new FileInputStream( arch );datos.load( in );in.close( );return datos;
}}
Cierra el “canal”
En el método cargarInfoCampeonato de la clase Campeonato …
public class Campeonato{ …
private Properties cargarInfoCampeonato( File arch ){
Properties datos = new Properties( );FileInputStream in = new FileInputStream( arch );datos.load( in );in.close( );return datos;
}}
Retorna los “datos” que es un objeto de la clase Properties
Qué contiene un objeto de la clase“Properties” ?
• Clase Properties de JAVA– Representa un conjunto de propiedades “persistentes”, es
decir que pueden ser almacenadas en un archivo.
campeonato.equipos = 5campeonato.nombre0 = A.C.Milancampeonato.nombre1 = Intercampeonato.nombre2 = Juventuscampeonato.nombre3 = Romacampeonato.nombre4 = Lazio
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
Archivo llamado “equipos.properties”(en el disco duro)
Objeto llamado “datos” de tipo Properties (en memoria principal)
El archivo equipos.properties
• Es un archivo de texto que contiene una lista de propiedades
• Cada propiedad es una línea del archivo y estádefinida como:
– nombre = valor– campeonato.equipos = 5
Qué contiene un objeto de la clase“Properties” ?
• Clase Properties de JAVA– Representa un conjunto de propiedades “persistentes”, es
decir que pueden ser almacenadas en un archivo.
campeonato.equipos = 5campeonato.nombre0 = A.C.Milancampeonato.nombre1 = Intercampeonato.nombre2 = Juventuscampeonato.nombre3 = Romacampeonato.nombre4 = Lazio
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
Archivo llamado “equipos.properties”(en el disco duro)
Objeto llamado “datos” de tipo Properties (en memoria principal)
El objeto llamado “datos” de la clase Properties
• Tiene métodos para obtener el valor de sus elementos
• Ejemplo:– String valor = datos.getProperty(“campeonato.nombre0”)
nombre = valor
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
El objeto llamado “datos” de la clase Properties
• Tiene métodos para obtener el valor de sus elementos
• Ejemplo:– String valor = datos.getProperty(“campeonato.nombre0”)
nombre = valor
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datosRetorna el “valor” del “nombre”campeonato.nombre0, que es “A.C. Milan”
Volvamos al método cargarInfoCampeonato de la clase
Campeonato …public class Campeonato{ …
private Properties cargarInfoCampeonato( File archivoInfoCampeonato ){
Properties datos = new Properties( );FileInputStream in = new FileInputStream( archivoInfoCampeonato );datos.load( in );in.close( );return datos;
}}
Retorna los “datos” que es un objeto de la clase Properties
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
Volvamos al método constructor de la clase Campeonato (paso 4) …
public class Campeonato{ …
public Campeonato( File archivoInfoCampeonato ){
Properties datos = cargarInfoCampeonato( archivoInfoCampeonato );inicializarEquipos( datos );inicializarTablaGoles( maxEquipos );
}}
Retorna los “datos” que es un objeto de la clase Properties
Se carga la información del campeonato, a partir del archivo
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
Continuemos con el método constructor de la clase Campeonato (paso 5) …
public class Campeonato{ …
public Campeonato( File archivoInfoCampeonato ){
Properties datos = cargarInfoCampeonato( archivoInfoCampeonato );inicializarEquipos( datos );inicializarTablaGoles( maxEquipos );
}}
Inicializa (llena) el arreglo de equipos a partir de la información contenida en el objeto “datos”
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
En el método inicializarEquipos de la clase Campeonato …
public class Campeonato{ …private void inicializarEquipos( Properties datos ) {
String strNumeroEquipos = datos.getProperty("campeonato.equipos");int numeroEquipos = Integer.parseInt(strNumeroEquipos);equipos = new Equipo[ numeroEquipos ];maxEquipos = numeroEquipos;
for (int i = 0; i < numeroEquipos; i++) {
String nombreEquipo = datos.getProperty("campeonato.nombre"+ i);Equipo nuevo = new Equipo( nombreEquipo );equipos[ i ] = nuevo;
}}
Obtiene el valor del nombre “campeonato.equipos” que contiene una cadena de caracteres con el número de equipos
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
En el método inicializarEquipos de la clase Campeonato …
public class Campeonato{ …private void inicializarEquipos( Properties datos ) {
String strNumeroEquipos = datos.getProperty("campeonato.equipos");int numeroEquipos = Integer.parseInt(strNumeroEquipos);equipos = new Equipo[ numeroEquipos ];maxEquipos = numeroEquipos;
for (int i = 0; i < numeroEquipos; i++) {
String nombreEquipo = datos.getProperty("campeonato.nombre"+ i);Equipo nuevo = new Equipo( nombreEquipo );equipos[ i ] = nuevo;
}}
Obtiene el valor numérico de la cantidad de equipos
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
En el método inicializarEquipos de la clase Campeonato …
public class Campeonato{ …private void inicializarEquipos( Properties datos ) {
String strNumeroEquipos = datos.getProperty("campeonato.equipos");int numeroEquipos = Integer.parseInt(strNumeroEquipos);equipos = new Equipo[ numeroEquipos ];maxEquipos = numeroEquipos;
for (int i = 0; i < numeroEquipos; i++) {
String nombreEquipo = datos.getProperty("campeonato.nombre"+ i);Equipo nuevo = new Equipo( nombreEquipo );equipos[ i ] = nuevo;
}}
Crea el arreglo de equipos con un tamaño igual a la cantidad de equipos
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
En el método inicializarEquipos de la clase Campeonato …
public class Campeonato{ …private void inicializarEquipos( Properties datos ) {
String strNumeroEquipos = datos.getProperty("campeonato.equipos");int numeroEquipos = Integer.parseInt(strNumeroEquipos);equipos = new Equipo[ numeroEquipos ];maxEquipos = numeroEquipos;
for (int i = 0; i < numeroEquipos; i++) {
String nombreEquipo = datos.getProperty("campeonato.nombre"+ i);Equipo nuevo = new Equipo( nombreEquipo );equipos[ i ] = nuevo;
}}
Inicializa el atributo
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
En el método inicializarEquipos de la clase Campeonato …
public class Campeonato{ …private void inicializarEquipos( Properties datos ) {
String strNumeroEquipos = datos.getProperty("campeonato.equipos");int numeroEquipos = Integer.parseInt(strNumeroEquipos);equipos = new Equipo[ numeroEquipos ];maxEquipos = numeroEquipos;
for (int i = 0; i < numeroEquipos; i++) {
String nombreEquipo = datos.getProperty("campeonato.nombre"+ i);Equipo nuevo = new Equipo( nombreEquipo );equipos[ i ] = nuevo;
}}
Carga uno a uno los nombres de los equipos
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
En el método inicializarEquipos de la clase Campeonato …
public class Campeonato{ …private void inicializarEquipos( Properties datos ) {
String strNumeroEquipos = datos.getProperty("campeonato.equipos");int numeroEquipos = Integer.parseInt(strNumeroEquipos);equipos = new Equipo[ numeroEquipos ];maxEquipos = numeroEquipos;
for (int i = 0; i < numeroEquipos; i++) {
String nombreEquipo = datos.getProperty("campeonato.nombre"+ i);Equipo nuevo = new Equipo( nombreEquipo );equipos[ i ] = nuevo;
}}
Crea el objeto de la clase Equipo
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
En el método inicializarEquipos de la clase Campeonato …
public class Campeonato{ …private void inicializarEquipos( Properties datos ) {
String strNumeroEquipos = datos.getProperty("campeonato.equipos");int numeroEquipos = Integer.parseInt(strNumeroEquipos);equipos = new Equipo[ numeroEquipos ];maxEquipos = numeroEquipos;
for (int i = 0; i < numeroEquipos; i++) {
String nombreEquipo = datos.getProperty("campeonato.nombre"+ i);Equipo nuevo = new Equipo( nombreEquipo );equipos[ i ] = nuevo;
}}
Adiciona el nuevo equipo al arreglo
campeonato.equipos 5
campeonato.nombre0 A.C.Milan
campeonato.nombre1 Inter
campeonato.nombre2 Juventus
campeonato.nombre3 Roma
campeonato.nombre4 Lazio
datos
Continuemos con el método constructor de la clase Campeonato (paso 6) …
public class Campeonato{ …
public Campeonato( File archivoInfoCampeonato ){
Properties datos = cargarInfoCampeonato( archivoInfoCampeonato );inicializarEquipos( datos );inicializarTablaGoles( maxEquipos );
}}
Inicializa la tabla de goles (con los valores SIN_JUGAR e INVALIDO)
10 2 3 4
A.C. Milan 0
Inter 1Juventus 2
Roma 3
Lazio 4
SIN_JUGAR INVALIDO
Volvamos al método cargarEquipos …
public class InterfazCampeonato extends JFrame{ …
public void cargarEquipos( ){
File archivoCampeonato = null;
JFileChooser fc = new JFileChooser( "./data" );fc.setDialogTitle( "Abrir archivo de campeonato" );int resultado = fc.showOpenDialog( this );
if( resultado == JFileChooser.APPROVE_OPTION ){
archivoCampeonato = fc.getSelectedFile( );campeonato = new Campeonato( archivoCampeonato );
}}
}Se llama al método constructor de la clase Campeonato, que recibe como parámetro, el archivo
Volvamos a la selección del archivo
El usuario genera un evento oprimiendo el botón. Se dispara el método cargarEquipos de la ventana principal (clase InterfazCampeonato)
En el método cargarInfoCampeonato de la clase Campeonato se pueden generar
excepciones … (pag. 319)
public class Campeonato{ …
private Properties cargarInfoCampeonato( File archivoInfoCampeonato ){
Properties datos = new Properties( );FileInputStream in = new FileInputStream( archivoInfoCampeonato );datos.load( in );in.close( );return datos;
}}
Genera excepción si no encuentra el archivo
En el método cargarInfoCampeonato de la clase Campeonato se pueden generar
excepciones … (pag. 231)
public class Campeonato{ …
private Properties cargarInfoCampeonato( File archivoInfoCampeonato ){
Properties datos = new Properties( );FileInputStream in = new FileInputStream( archivoInfoCampeonato );datos.load( in );in.close( );return datos;
}}
Genera excepción si la manera como estáescrito el archivo no es “nombre=valor”
Entonces …public class Campeonato{ …
private Properties cargarInfoCampeonato(File archivoInfoCampeonato) throws Exception{
Properties datos = new Properties( );FileInputStream in = null;try{
in = new FileInputStream(archivoInfoCampeonato);} catch (Exception e){
throw new Exception("El archivo no existe!");}try{
datos.load(in);in.close();
} catch (Exception e){
throw new Exception("El formato del archivo no es válido!");}return datos;
}}
Disparar la excepción si no encuentra el archivo
Disparar la excepción si el archivo no es válido