Triqui en Qt4 Andrés Becerra Sandoval October 2, 2014 1 Triqui 1.1 Idea Crear un programa para jugar triqui, entre dos jugadores humanos, alternándose. 1.2 Requerimientos • Proveer una interfaz gráfica para jugar triqui en la que las jugadas se hacen con el apuntador. • Registrar el estado del tablero en todo momento. • Calcular si el juego se termina por empate o victoria de algún jugador. • Después de terminar un juego, permitir iniciar uno nuevo. 2 Clases y responsabilidades tableroTriqui: representa el tablero del juego. Responsabilidades: • reporta y cambia el estado de una casilla del triqui • averigua si hay empate • averigua si un jugador gana • reinicia el tablero colaboraciones: ninguna juegoTriqui: representa el juego. Responsabilidades: • registra una jugada • reporta el estado de una casilla del triqui • reporta el estado del juego {jugando, empatado, ganado} 1 • reporta el turno actual • reinicia el juego • cambia el turno de un jugador al otro colaboraciones: tableroTriqui boton: representa un botón en la interfaz gráfica • reporta la fila del botón • reporta la columna del botón • muestra y actualiza el estado de una casilla del tablero colaboraciones: ninguna ventana: representa la interfaz gráfica de la aplicación • crea los botones para jugar • cambia el estado del juego cuando se presionan los botones • actualiza el estado de un botón después de una jugada • muestra el estado del juego colaboraciones: boton, juegoTriqui 3 Aspirando al bajo acoplamiento Para mantener el bajo acoplamiento las clases TableroTriqui y JuegoTriqui no tienen dependencias de Qt. Representan el «modelo», la lógica del juego triqui que no depende de la forma de jugarlo (con interfaz gráfica, en la línea de comandos, etc.). Ambas utilizan las siguientes enumeraciones para representar el estado de las casillas en el tablero, del juego, del turno y para saber donde ganó un jugador en un momento dado: Listing 1: enums.h #i f n d e f ENUMS_H #define ENUMS_H enum enum enum enum Turno { uno=1, dos=2 } ; E s t a d o C a s i l l a { v a c i a =0, juno =1, j d o s =2 } ; EstadoJuego { jugando , empate , ganado } ; DondeGano{ f i l a , columna , d i a g o n a l } ; #endif 2 Observe que los valores de Turno, uno y dos, son iguales a los EstadoCasilla, juno y jdos. La clase tablero triqui está definida a continuación: Listing 2: tableroTriqui.h class TableroTriqui { public : TableroTriqui ( ) ; E s t a d o C a s i l l a e s t a d o C a s i l l a ( int f i l , int c o l ) const ; DondeGano dondeGano ( ) const ; int numeroGano ( ) const ; bool c a m b i a C a s i l l a ( int f i l , int c o l , Turno t u r n o ) ; bool hayEmpate ( ) ; bool gana ( Turno turno , int f i l , int c o l ) ; void r e i n i c i a r ( ) ; private : s t a t i c const int tam = 3 ; E s t a d o C a s i l l a t a b l e r o [ tam ] [ tam ] ; DondeGano m_dondeGano ; int m_numeroGano ; // d i a g o n a l , f i l a o columna // que numero de f i l a , c o l o d i a g bool ganaEnDiagonal1 ( Turno ) ; // d i a g o n a l uno bool ganaEnDiagonal2 ( Turno ) ; // d i a g o n a l dos bool ganaEnFila ( int f i l , Turno ) ; bool ganaEnColumna ( int c o l , Turno ) ; T a b l e r o T r i q u i ( const T a b l e r o T r i q u i &); (\) (/) }; Al tener toda la lógica del tablero en una clase se espera que este código no cambie al portarlo a otro tipo de interfaz gráfica. La lógica del juego está en la clase juegoTriqui, a continuación: Listing 3: juegoTriqui.h class TableroTriqui ; class JuegoTriqui { public : JuegoTriqui ( ) ; ~JuegoTriqui ( ) ; bool j u g a r ( int f i l a , int columna ) ; E s t a d o C a s i l l a e s t a d o C a s i l l a ( int f i l a , int columna ) ; void r e i n i c i a r ( ) ; EstadoJuego e s t a d o ( ) ; Turno t u r n o ( ) ; 3 DondeGano dondeGano ( ) ; int numeroGano ( ) ; private : void cambio_de_Turno ( ) ; Turno m_turno ; EstadoJuego m_estado ; TableroTriqui ∗ tableroTriqui ; }; #endif JuegoTriqui maneja el ciclo de vida de un tableroTriqui y actúa como una fachada (facade) hacia él. 4 Diagrama de clases A continuación se representan las relaciones de agregación y herencia entre las clases Algunos comentarios: • La ventana de la aplicación maneja el ciclo de vida de un juegoTriqui, pero no interactúa directamente con el tableroTriqui • La «vista», es decir, la representación gráfica del juego, a través de una matriz de botones, es diferente del modelo (tableroTriqui) pero se mantienen en sincronía. • Los botones almacenan la fila y columna a la que pertenecen para poder actualizar su estado de acuerdo a tableroTriqui 4 El slot botonPresionado actúa como controlador sincronizando el modelo (juegoTriqui) con la vista (botonesJuego) que es una matriz de botones: Listing 4: ventana.cpp void Ventana : : b o t o n P r e s i o n a d o ( ) { int f i l a ; i n t columna ; EstadoJuego e s t a d o J u e g o ; int r ; Boton ∗ b o t o n R e c i e n P r e s i o n a d o = q o b j e c t _ c a s t <Boton ∗>( s e n d e r ( ) ) ; f i l a = b o t o n R e c i e n P r e s i o n a d o −>o b t e n e r F i l a ( ) ; columna = b o t o n R e c i e n P r e s i o n a d o −>obtenerColumna ( ) ; i f ( j u e g o −>j u g a r ( f i l a , columna ) ) { a c t u a l i z a r ( botonRecienPresionado ) ; e s t a d o J u e g o = j u e g o −>e s t a d o ( ) ; i f ( e s t a d o J u e g o==ganado ) { QString mensajeTriunfo ; i f ( j u e g o −>t u r n o ( ) == uno ) m e n s a j e T r i u n f o = Q S t r i n g ( "Gana␣ e l ␣ Primer ␣ j u g a d o r , ␣ \n␣ Desean ␣ j u g a r ␣ o t r o ? " ) ; else m e n s a j e T r i u n f o = Q S t r i n g ( "Gana␣ e l ␣ Segundo ␣ j u g a d o r , ␣ \n␣ Desean ␣ j u g a r ␣ o t r o ? " ) ; r = QMessageBox : : q u e s t i o n ( 0 , " Fin ␣ d e l ␣ j u e g o " , m e n s a j e T r i u n f o , QMessageBox : : Yes | QMess i f ( r == QMessageBox : : No) close (); else { j u e g o −> r e i n i c i a r ( ) ; reiniciar (); } } e l s e i f ( e s t a d o J u e g o==empate ) { r = QMessageBox : : q u e s t i o n ( 0 , " Fin ␣ d e l ␣ j u e g o " , "Hay␣ empate , ␣ d e s e a n ␣ j u g a r ␣ o t r a ␣ v e z ? " , QM i f ( r == QMessageBox : : No) close (); else { j u e g o −> r e i n i c i a r ( ) ; reiniciar (); } } } e l s e { // ya s e h a b i a j u g a d o en l a c a s i l l a Phonon : : MediaObject ∗ mediaObject = Phonon : : c r e a t e P l a y e r ( Phonon : : MusicCategory , Phonon : : M mediaObject−>p l a y ( ) ; } } 5 Código fuente En https://github.com/abecerra/triqui2/ encuentran la implementación. 5