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… Minesweeper 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,” boton_on(17) VALUE ‘<pisando Numero de linea para el boton 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,” conta_radar TYPE i,” Icono adjunto al boton Contador de bombas limitrofes a la celda conta_heridas TYPE i,” conta_detect TYPE i,” Contador de errores 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.” ——————————— msg_1 = ‘Bombas pisadas: 0 mensaje ‘. 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