Categorias

Campo Minado em ABAP

Use este código para criar e jogar Campo Minado em ABAP!

*&==============================================================
*&                Developed by ROMAN LOPEZ NAVARRO                  *
*&           https://personales.com/espana/madrid/abap/              *
*&           https://www.geocities.com/romlopabap/                   *
*&==============================================================
*&---------------------------------------------------------------------*
*& Report ZBUSCAMIN                                                 *
*&---------------------------------------------------------------------*
* Una celda marcada como bomba ' B ' no admite ser marcada como detecta-
* da ' D ' ya que implicitamente esta detectada.
* Una vez que el juego acabo no se muestran mas mensajes aunque si se
* permite seguir explorando las celdas ocultas.
* Si algunas de las celdas marcadas como detectadas son incorrectas, es-
* tas se muestran en un nuevo listado.
* Evidentemente NUM_BOMB debe ser superior o igual a MAX_HERI.
* El boton que aparece debajo del tablero indica la accion actual del
* usuario, y que puede ser una de las dos siguientes:
* 1.-  : La casilla se marca con el numero de bombas que
*                        rodean a dicha casilla.
* 2.- : La casilla se marca con una < D > (aunque el
*                        jugador se haya equivocado y no haya bomba).
* Para marcar bombas (detectar bombas) hay que hacer clic en el boton
* hasta que aparezca el texto ''.
*&---------------------------------------------------------------------*
   REPORT ZPC_TESTEG3 NO STANDARD PAGE HEADING.
   INCLUDE .

   CONSTANTS:
  LINE_INI TYPE I VALUE 2,"       Primera linea de comienzo de escritura
  POSINI TYPE I VALUE 4,"       Justificacion a la izquierda del tablero
* NUM_BOMB TYPE I VALUE 15,"              Numero de bombas en el tablero
* MAX_HERI TYPE I VALUE 1,"              Numero de errores permitidos
  FILAS TYPE I VALUE 10,"                    Numero de filas del tablero
  COLUMNAS TYPE I VALUE 10,"              Numero de columnas del tablero
  BOMBA(3) VALUE ' B ',"                           Simbolo para la bomba
  DETECT(3) VALUE ' D ',"                   Simbolo para bomba detectada
  LINE_MSG TYPE I VALUE 25,"           Numero de linea para los mensajes
  LINE_BOTON TYPE I VALUE 27,"             Numero de linea para el boton
  BOTON_ON(17)  VALUE '',
     BOTON_OFF(17) VALUE '',
     ICON_ON  LIKE ICONS-L2 VALUE '@1A@',
     ICON_OFF LIKE ICONS-L2 VALUE '@1C@',
     ICON_ERR LIKE ICONT-ID VALUE '@3C@'.


   DATA:
     MSG_1(45),"Mensaje
     GAME_OVER,"Flag de partida terminada
     STR_TMP(255)," Variable string temporal
     BOTON(17),"                             Texto del boton
     ICON_BOTON LIKE ICONT-ID,"        Icono adjunto al boton
     CONTA_RADAR TYPE I,"  Contador de bombas limitrofes a la celda
     CONTA_HERIDAS TYPE I,"                    Contador de errores
     CONTA_DETECT TYPE I,"  Contador de celdas marcadas como detectadas
     CONTA_GENERAL TYPE I,"            conta_detect + conta_heridas
     CELL_NAME LIKE DD03D-FIELDNAME,"           Nombre de una celda
     FILA      LIKE DATATYPE-INTEGER2,"       Fila de una celda
     COLUMNA   LIKE DATATYPE-INTEGER2,"      Columna de una celda
     FILA_CHAR2(2),
     COLUMNA_CHAR2(2).

   DATA:
     BEGIN OF ITAB_LET,
       1(3), 2(3), 3(3), 4(3), 5(3), 6(3), 7(3), 8(3), 9(3), 10(3),
     END OF ITAB_LET,

* Estructura con todas las celdas del tablero
     BEGIN OF ITAB,
       1 LIKE ITAB_LET, 2 LIKE ITAB_LET, 3 LIKE ITAB_LET,
       4 LIKE ITAB_LET, 5 LIKE ITAB_LET, 6 LIKE ITAB_LET,
       7 LIKE ITAB_LET, 8 LIKE ITAB_LET, 9 LIKE ITAB_LET,
       10 LIKE ITAB_LET,
     END OF ITAB,

* Estructura con las bombas pisadas
     BIS_ITAB LIKE ITAB,

* Estructura con todas las bombas calculadas iniciales
     BOMB_ITAB LIKE ITAB.

  FIELD-SYMBOLS: , , , .

   SELECTION-SCREEN BEGIN OF BLOCK BLOQUE1 WITH FRAME TITLE TITULO1.
     SELECTION-SCREEN: BEGIN OF LINE,
       COMMENT 1(16) COMENT1,
       POSITION 20.
       PARAMETERS NUM_BOMB(2) TYPE N DEFAULT 15.
     SELECTION-SCREEN END OF LINE.

     SELECTION-SCREEN: BEGIN OF LINE,
       COMMENT 1(18) COMENT2.
       POSITION 20.
       PARAMETERS MAX_HERI(2) TYPE N DEFAULT 1.
     SELECTION-SCREEN END OF LINE.
   SELECTION-SCREEN END OF BLOCK BLOQUE1.

************************************************************************
*                             INITIALIZATION                        *
************************************************************************
   INITIALIZATION.
     TITULO1 = 'Opciones de usuario'.
     COMENT1 = 'Numero de bombas'.
     COMENT2 = 'Errores permitidos'.
************************************************************************
*                          START-OF-SELECTION                       *
************************************************************************
   START-OF-SELECTION.

     PERFORM DISPLAY_TABLERO.
     PERFORM ASIGNAR_BOMBAS.

************************************************************************
*                         AT LINE-OF-SELECTION                      *
************************************************************************
   AT LINE-SELECTION.

     GET CURSOR FIELD CELL_NAME.
*----------------------------------------------------------------------*
*                      Cambiar el texto del boton                   *
*----------------------------------------------------------------------*
* Solo se permite si la partida no ha terminado. Cuando una partida ha
* terminado el boton queda permanentemente en estado ON.
     IF CELL_NAME = 'BOTON' AND GAME_OVER IS INITIAL.
       PERFORM CHANGE_BOTON.
     ENDIF.
*----------------------------------------------------------------------*
*     Obtener el valor de la celda seleccionada en todas las tablas *
*----------------------------------------------------------------------*
     CHECK CELL_NAME CS 'ITAB-'.
     ASSIGN (CELL_NAME) TO ." ----------- Tabla tablero ctual
     CONCATENATE 'BIS_' CELL_NAME INTO STR_TMP.
     ASSIGN (STR_TMP) TO ." -------------- Tabla bombas pisadas
     CONCATENATE 'BOMB_' CELL_NAME INTO STR_TMP.
     ASSIGN (STR_TMP) TO ." ------ Tabla con todas las bombas

     SUBTRACT 1 FROM SY-LSIND.
*&====================================================================&*
*&                           Detectar bomba                           &*
*&             Marcar con una 'D' la celda seleccionada               &*
*&====================================================================&*
     IF BOTON = BOTON_OFF.
*   Si el juego ha terminado no permitir detectar mas bombas (para evi-
*   tar mensajes cruzados de la rutina de deteccion). Sobra, porque el
*   boton solo puede estar en OFF si la partida no ha acabado.
*   CHECK GAME_OVER IS INITIAL.
*   Comprobar que no es una bomba ya pisada ni ya detectada
       CHECK  NE BOMBA AND  NE DETECT.
       MODIFY LINE SY-LILLI FIELD VALUE   FROM DETECT
                            FIELD FORMAT  COLOR COL_POSITIVE.

        = DETECT.

       ADD 1 TO CONTA_DETECT.

       CONTA_GENERAL = CONTA_HERIDAS + CONTA_DETECT.

       IF CONTA_GENERAL = NUM_BOMB.

         PERFORM CHECK_SUCCESS.

       ENDIF.

       EXIT.

     ENDIF.

*&====================================================================&*
*&                            Pisar celdas                            &*
*&  Muestra si la celda es una bomba o bien las bombas que la rodean  &*
*&====================================================================&*
     IF  = DETECT. SUBTRACT 1 FROM CONTA_DETECT. ENDIF.
* Si la celda es una bomba, marcarla con una ' B '
     IF  = BOMBA.
       PERFORM X_BOMBA.
* Si la celda no es una bomba, mostrar las bombas limitrofes
     ELSE.
       PERFORM OBTAIN_COORDENADAS.
       PERFORM OBTAIN_LIMITS.
     ENDIF.

     SET CURSOR 0 0.
*&---------------------------------------------------------------------*
*&      Form  DISPLAY_TABLERO
*&---------------------------------------------------------------------*
   FORM DISPLAY_TABLERO.

     DATA: CABLET(255), LONGITUD TYPE I, NUMFILA(2), N TYPE I.

     SKIP TO LINE LINE_INI.

     CABLET = '  | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10|'.

     LONGITUD = STRLEN( CABLET ).

     WRITE AT POSINI CABLET.

     ULINE AT /POSINI(LONGITUD).

     NEW-LINE.

   DO FILAS TIMES." ----------------------------------- Filas

       MOVE SY-INDEX TO NUMFILA.

       ASSIGN COMPONENT SY-INDEX OF STRUCTURE ITAB TO .

       POSITION POSINI.

       WRITE: NUMFILA NO-GAP RIGHT-JUSTIFIED.

       WRITE: SY-VLINE NO-GAP.

     DO COLUMNAS TIMES." ------------------------------ Columnas

         ASSIGN COMPONENT SY-INDEX OF STRUCTURE  TO .

         WRITE:  HOTSPOT NO-GAP,

                SY-VLINE NO-GAP.

       ENDDO.

       ULINE at /POSINI(LONGITUD). NEW-LINE.

     ENDDO.

     SKIP TO LINE LINE_MSG." ------------------------- Mensaje

     MSG_1 = 'Bombas pisadas: 0  '.

     WRITE AT: POSINI MSG_1 INTENSIFIED OFF,

               SY-LINSZ SPACE.

     SKIP 1.

     ICON_BOTON = ICON_ON." --------------- Icono del boton

     WRITE AT POSINI ICON_BOTON AS ICON.

     BOTON = BOTON_ON." ------------------------- Texto del boton

     CLEAR N.

     N = POSINI + 4.

     WRITE AT N BOTON HOTSPOT COLOR COL_TOTAL.

   ENDFORM.                    " DISPLAY_TABLERO

*&---------------------------------------------------------------------*
*&      Form  ASIGNAR_BOMBAS
*&---------------------------------------------------------------------*
* Llena la tabla BOMB_ITAB con las bombas calculadas
*&---------------------------------------------------------------------*
   FORM ASIGNAR_BOMBAS.

     DATA: CHAR2(2) TYPE C, FIELDNAME(255), CONTA_BOMBAS TYPE I.

     PERFORM INI_SEMILLA.

     WHILE CONTA_BOMBAS LT NUM_BOMB.
*------------------------------------------------------------------ Fila
       CALL FUNCTION 'RANDOM_I2'
            EXPORTING RND_MIN = 1   RND_MAX   = 10
            IMPORTING RND_VALUE = FILA.

       MOVE FILA TO CHAR2.

       CONCATENATE 'BOMB_ITAB-' CHAR2 INTO FIELDNAME.

*--------------------------------------------------------------- Columna
       CALL FUNCTION 'RANDOM_I2'
            EXPORTING RND_MIN = 1   RND_MAX   = 10
            IMPORTING RND_VALUE = COLUMNA.

       MOVE COLUMNA TO CHAR2.

       CONCATENATE FIELDNAME '-' CHAR2 INTO FIELDNAME.

       ASSIGN (FIELDNAME) TO .

       IF  IS INITIAL.

          = BOMBA.

         ADD 1 TO CONTA_BOMBAS.

       ENDIF.

     ENDWHILE.

   ENDFORM.                    " ASIGNAR_BOMBAS
*&---------------------------------------------------------------------*
*&      Form  INI_SEMILLA
*&---------------------------------------------------------------------*
* Asegura que la semilla sera aleatoria.
*----------------------------------------------------------------------*
   FORM INI_SEMILLA.

     DO 5 TIMES.

       CALL FUNCTION 'RANDOM_I2'
            EXPORTING RND_MIN = 1   RND_MAX   = 10
            IMPORTING RND_VALUE = FILA.

     ENDDO.

   ENDFORM.                    " INI_SEMILLA

*&---------------------------------------------------------------------*
*&      Form  OBTAIN_COORDENADAS
*&---------------------------------------------------------------------*
   FORM OBTAIN_COORDENADAS.

     DATA  STRING_COMPONENTES LIKE DD03D-FIELDNAME OCCURS 0.

     SPLIT CELL_NAME AT '-' INTO TABLE STRING_COMPONENTES.

     READ TABLE STRING_COMPONENTES INDEX 2 INTO FILA.
     READ TABLE STRING_COMPONENTES INDEX 3 INTO COLUMNA.

   ENDFORM.                    " OBTAIN_COORDENADAS
*&---------------------------------------------------------------------*
*&      Form  OBTAIN_LIMITS
*&---------------------------------------------------------------------*
* Averigua si las celdas limitrofes a la seleccionada tienen una bomba.
*----------------------------------------------------------------------*
   FORM OBTAIN_LIMITS.

     CLEAR CONTA_RADAR.

* Celda N

     FILA_CHAR2    = FILA - 1.

     COLUMNA_CHAR2 = COLUMNA.

     PERFORM RADAR.

* Celda NW

     FILA_CHAR2 = FILA - 1.

     COLUMNA_CHAR2 = COLUMNA - 1.

     PERFORM RADAR.

* Celda NE

     FILA_CHAR2 = FILA - 1.

     COLUMNA_CHAR2 = COLUMNA + 1.

     PERFORM RADAR.

* Celda S

     FILA_CHAR2 = FILA + 1.

     COLUMNA_CHAR2 = COLUMNA.

     PERFORM RADAR.

* Celda SW

     FILA_CHAR2 = FILA + 1.

     COLUMNA_CHAR2 = COLUMNA - 1.

     PERFORM RADAR.

* Celda SE

     FILA_CHAR2 = FILA + 1.

     COLUMNA_CHAR2 = COLUMNA + 1.

     PERFORM RADAR.

* Celda E

     FILA_CHAR2 = FILA.

     COLUMNA_CHAR2 = COLUMNA - 1.

     PERFORM RADAR.

* Celda W

     FILA_CHAR2 = FILA.

     COLUMNA_CHAR2 = COLUMNA + 1.

     PERFORM RADAR.

      = CONTA_RADAR.

*  SY-LILLI = LINE_INI * ( FILA + 1 ).

     MODIFY LINE SY-LILLI FIELD VALUE   FROM CONTA_RADAR
                          FIELD FORMAT  COLOR COL_TOTAL.

   ENDFORM.                    " OBTAIN_LIMITS

*&---------------------------------------------------------------------*
*&      Form  RADAR
*&---------------------------------------------------------------------*
* Averigua si la celda pasada es una bomba.
*----------------------------------------------------------------------*
   FORM RADAR.

     CHECK FILA_CHAR2 NE '0'  AND COLUMNA_CHAR2 NE '0'  AND
           FILA_CHAR2 NE '11' AND COLUMNA_CHAR2 NE '11'.

     CONCATENATE 'BOMB_ITAB-' FILA_CHAR2 '-' COLUMNA_CHAR2 INTO STR_TMP.

     ASSIGN (STR_TMP) TO .

     IF  = BOMBA. ADD 1 TO CONTA_RADAR. ENDIF.

   ENDFORM.                    " RADAR
*&---------------------------------------------------------------------*
*&      Form  X_BOMBA
*&---------------------------------------------------------------------*
* Marca la bomba en el tablero y muestra el mensaje correspondiente.
*----------------------------------------------------------------------*
   FORM X_BOMBA.

     DATA CONTA_CHAR(3).

* Compruebo que la bomba no ha sido pisada con anterioridad
     CHECK  NE BOMBA.

* Marcar la bomba en el tablero
      = BOMBA.

     MODIFY LINE SY-LILLI FIELD VALUE   FROM 
                          FIELD FORMAT  COLOR COL_NEGATIVE.

* Seguir solo si la partida no esta acabada
     CHECK GAME_OVER IS INITIAL.

     ADD 1 TO CONTA_HERIDAS.

     MOVE CONTA_HERIDAS TO CONTA_CHAR.

     CONCATENATE 'Bombas pisadas: ' CONTA_CHAR INTO MSG_1.

     CLEAR SY-LISEL.

     MODIFY LINE LINE_MSG FIELD VALUE MSG_1.

     IF CONTA_HERIDAS = MAX_HERI.

       MSG_1 =  'Has pisado demasiadas bombas!'.

       MODIFY LINE LINE_MSG FIELD VALUE MSG_1
                            FIELD FORMAT MSG_1 COLOR COL_NEGATIVE
                            INVERSE.

       GAME_OVER = 'X'.

     ENDIF.

     CONTA_GENERAL = CONTA_HERIDAS + CONTA_DETECT.

     IF CONTA_GENERAL = NUM_BOMB.

       PERFORM CHECK_SUCCESS.

     ENDIF.

   ENDFORM.                    " X_BOMBA
*&---------------------------------------------------------------------*
*&      Form  CHANGE_BOTON
*&---------------------------------------------------------------------*
* Cambia el titulo del boton de BOTON_ON a BOTON_OFF y vicevera.
*----------------------------------------------------------------------*
   FORM CHANGE_BOTON.

     DATA: BOTON_TMP LIKE BOTON, COLOR_TMP TYPE I, NEW_ICON LIKE
ICONS-L2.

     CASE BOTON.
       WHEN BOTON_ON.
         BOTON = BOTON_OFF. NEW_ICON = ICON_OFF. COLOR_TMP = 5.
       WHEN BOTON_OFF.
         BOTON = BOTON_ON. NEW_ICON = ICON_ON. COLOR_TMP = 3.
     ENDCASE.

     WRITE BOTON TO BOTON_TMP.

     ICON_PREPARE_FOR_MODIFY NEW_ICON.

     MODIFY LINE LINE_BOTON FIELD VALUE BOTON FROM BOTON_TMP
                                        ICON_BOTON FROM NEW_ICON
                            FIELD FORMAT BOTON COLOR = COLOR_TMP.

     SET CURSOR 1 1.

   ENDFORM.                    " CHANGE_BOTON
*&---------------------------------------------------------------------*
*&      Form  CHECK_SUCCESS
*&---------------------------------------------------------------------*
* La partida ha terminado. Comprueba si se ha ganado.
*----------------------------------------------------------------------*
   FORM CHECK_SUCCESS.

     DATA: N TYPE I, M TYPE I, FILA_TMP TYPE I, COLUMNA_TMP TYPE I,
           FILA_TMP_FLOAT TYPE F, FILA_CHAR3(3), COLUMNA_CHAR3(3),
           NEW_ICON LIKE ICONS-L2.

     FIELD-SYMBOLS: , .

     N = FILAS * COLUMNAS.

* Para mostrar un NUEVO listado con las detecciones incorrectas.
     ADD 1 TO SY-LSIND.
* ---------------------------------------------------------------------*
* FILA_TMP y COLUMNA_TMP guardan las coordenadas de la celda a partir de
* su posicion absoluta (SY-INDEX)
* Por ejemplo, el campo 19 esta en la segunda fila, novena columna; para
* un total de 10 filas y 10 columnas.
*----------------------------------------------------------------------*
     DO N TIMES.

       FILA_TMP_FLOAT = SY-INDEX / COLUMNAS.

       FILA_TMP = CEIL( FILA_TMP_FLOAT ).

       COLUMNA_TMP = SY-INDEX - ( COLUMNAS * FILA_TMP ) + COLUMNAS.

       MOVE: FILA_TMP TO FILA_CHAR3, COLUMNA_TMP TO COLUMNA_CHAR3.

       CONCATENATE 'ITAB-' FILA_CHAR3 '-' COLUMNA_CHAR3

       INTO STR_TMP. CONDENSE STR_TMP NO-GAPS.

       ASSIGN (STR_TMP) TO .

*   Se comprueba que la celda que se ha se¤alado como 'D' - Detectada,
*   realmente contiene una bomba.
       IF  = DETECT.

         CONCATENATE 'BOMB_ITAB-' FILA_CHAR3 '-' COLUMNA_CHAR3
                     INTO STR_TMP. CONDENSE STR_TMP NO-GAPS.

         ASSIGN (STR_TMP) TO .

         IF  NE BOMBA.

*       Mensaje(s) de celda(s) incorrecta(s) en nuevo listado.
           CONCATENATE 'La celda ' FILA_CHAR3 '-' COLUMNA_CHAR3
           ' no contenia ninguna bomba' INTO STR_TMP. WRITE STR_TMP.

           MSG_1 = 'Has perdido! Juega otra vez'.

           MODIFY LINE LINE_MSG FIELD VALUE MSG_1
                                FIELD FORMAT MSG_1 COLOR COL_NEGATIVE
                                                   INVERSE.

           GAME_OVER = 'X'." ---------------- Partida acabada

         ENDIF.

       ENDIF.

     ENDDO.

* Se pone el boton a ON (para no permitir detectar mas bombas tanto si
* la partida se ha ganado como si se ha perdido)
     NEW_ICON = ICON_ON.

     ICON_PREPARE_FOR_MODIFY NEW_ICON.

     BOTON = BOTON_ON.

     CLEAR SY-LISEL.

     MODIFY LINE LINE_BOTON FIELD VALUE  ICON_BOTON FROM NEW_ICON
                                         BOTON
                            FIELD FORMAT BOTON COLOR = 3.

* Mensaje de partida ganada (no se erro ninguna celda detectada)
     CHECK GAME_OVER IS INITIAL.

     MSG_1 = 'Enhorabuena! Ganaste la partida'.

     MODIFY LINE LINE_MSG FIELD VALUE  MSG_1
                          FIELD FORMAT MSG_1 COLOR COL_POSITIVE INVERSE.

     GAME_OVER = 'X'." ------------------------ Partida acabada

   ENDFORM.                    " CHECK_SUCCESS

Arquivos para Download:

Tela de Campo Minado em ABAP.doc