Minesweeper
Das bekannte Spiel Minesweeper in der SAP-Version. Leider ist alles in spanisch gehalten. Für das Spielen ist es nicht relevant, aber im Sourcecode ist es schon merkwürdig, wenn man nicht weiss, wofür ein Variablenname stehen könnte…
|
REPORT zz_minesweeper .
*&==============================================================
*& Developed by ROMAN LOPEZ NAVARRO *
*& http://personales.com/espana/madrid/abap/ *
*& http://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.- <pisando bombas> : La casilla se marca con el numero de bombas que
* rodean a dicha casilla.
* 2.- <marcando bombas>: 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 ‘<marcando bombas>’.
*&———————————————————————*
INCLUDE <icon>.
CONSTANTS:
line_ini TYPE i VALUE 2,” Primera linea de comienzo de escritura
posini TYPE i VALUE 4,” Justificacion a la izquierda del tablero
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 ‘<pisando bombas>’,
boton_off(17) VALUE ‘<marcando bombas>’,
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 TYPE i,” Fila de una celda
columna TYPE i,” 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: <fs1>, <fs2>, <fs3>, <fs4>.
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 <fs1>.” ——————- Tabla tablero actual
CONCATENATE ‘BIS_’ cell_name INTO str_tmp.
ASSIGN (str_tmp) TO <fs2>.” ——————— Tabla bombas pisadas
CONCATENATE ‘BOMB_’ cell_name INTO str_tmp.
ASSIGN (str_tmp) TO <fs3>.” ————— 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 <fs1> NE bomba AND <fs1> NE detect.
MODIFY LINE sy-lilli FIELD VALUE <fs1> FROM detect
FIELD FORMAT <fs1> COLOR col_positive.
<fs1> = 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 <fs1> = detect. SUBTRACT 1 FROM conta_detect. ENDIF.
* Si la celda es una bomba, marcarla con una ‘ B ‘
IF <fs3> = 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 <fs1>.
POSITION posini.
WRITE: numfila NO-GAP RIGHT-JUSTIFIED.
WRITE: sy-vline NO-GAP.
DO columnas TIMES.” ———————————– columnas
ASSIGN COMPONENT sy-index OF STRUCTURE <fs1> TO <fs2>.
WRITE: <fs2> 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 ‘QF05_RANDOM_INTEGER’
EXPORTING
ran_int_max = 10
ran_int_min = 1
IMPORTING
ran_int = fila
EXCEPTIONS
OTHERS = 2.
MOVE fila TO char2.
CONCATENATE ‘BOMB_ITAB-‘ char2 INTO fieldname.
*————————————————————— Columna
CALL FUNCTION ‘QF05_RANDOM_INTEGER’
EXPORTING
ran_int_max = 10
ran_int_min = 1
IMPORTING
ran_int = columna
EXCEPTIONS
OTHERS = 1.
MOVE columna TO char2.
CONCATENATE fieldname ‘-‘ char2 INTO fieldname.
ASSIGN (fieldname) TO <fs1>.
IF <fs1> IS INITIAL.
<fs1> = 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 ‘QF05_RANDOM_INTEGER’
EXPORTING
RAN_INT_MAX = 10
RAN_INT_MIN = 1
IMPORTING
RAN_INT = fila
EXCEPTIONS
OTHERS = 2.
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.
<fs1> = conta_radar.
MODIFY LINE sy-lilli FIELD VALUE <fs1> FROM conta_radar
FIELD FORMAT <fs1> 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 <fs3>.
IF <fs3> = 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 <fs1> NE bomba.
* Marcar la bomba en el tablero
<fs1> = bomba.
MODIFY LINE sy-lilli FIELD VALUE <fs1> FROM <fs1>
FIELD FORMAT <fs1> 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: <fs5>, <fs6>.
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 <fs6>.
* Se comprueba que la celda que se ha se¤alado como ‘D’ – Detectada,
* realmente contiene una bomba.
IF <fs6> = detect.
CONCATENATE ‘BOMB_ITAB-‘ fila_char3 ‘-‘ columna_char3
INTO str_tmp.
CONDENSE str_tmp NO-GAPS.
ASSIGN (str_tmp) TO <fs5>.
IF <fs5> 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
- 7. December: Excel Racing Simulation – Root Vole Race - 7. Dezember 2024
- 5. December: ABAPConf - 5. Dezember 2024
- 4. December: Only a lazy developer is a good developer - 4. Dezember 2024