152
ALGORITMICA Y PROGRAMACION POR OBJETOS I Nivel 6 Manejando Estructuras Contenedoras de 2 Dimensiones y Persistencia Marcela Hernández Hoyos

ALGORITMICA Y PROGRAMACION POR OBJETOS I

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

Motivación

:Cubo Ubicado en la posición i,j

fila i

Bodega

columna j

Motivación

fila i

Bodega

Cómo definir este tipo de estructura

columna j

Motivación

fila i

Bodega

Cómo definir este tipo de estructura

R// Con una MATRIZ

columna j

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)

Caso de estudio No. 1: Visor de Imágenes

El Visor de Imágenes

• Funcionalidad• Interfaz usuario• Formato BMP• Mundo

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 – …

Formato BMP

Pixel tiene un color

RojoVerdeAzul

0..255

0..255

0..255

El Visor de Imágenes –Interfaz usuario

El Visor de Imágenes – Mundo

IMAGEN: Único elemento del mundo Rojo

Verde

Azul

Se representa por medio de una MATRIZ

de 300x400

Contenedoras de 2 dimensiones: MATRICES

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){

}

Patrones de recorrido de matrices

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.

Caso de estudio: Campeonato de Fútbol

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

El Campeonato de Fútbol – Mundo

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

El Campeonato de Fútbol – Mundo

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

Dar la información sobre la tabla de posiciones

Construir la tabla de posiciones

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( ){

}

Persistencia y manejo del estado inicial

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.

El Concepto de Archivo

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 –Preguntas/Respuestas del Examen

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 !!!, …)

Ejemplo de archivos –Equipos del campeonato

Ejemplo de archivos –Equipos del campeonato

En qué se parecen estos dos archivos ?

Ejemplo de archivos –Equipos del campeonato

R1// Número de elementos

Ejemplo de archivos –Equipos del campeonato

R2// Para cada elemento, el valor de sus propiedades

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