Skip to Content

Learn how to use dynamic programming to create context nodes and UI elements in run time, how to use context menus, assistance classes and more, in a fun way; creating the clasic game: MineSweeper.

1.JPG

Let’s start:

Goto SE80 and create a new WD component:

2.JPG

3.JPG

Go to the context in MAIN view and create a new node called SETTINGS, with Cardinality 1:1 and Init. Lead Selection = X.

This node will store the settings of the game:  Number of columns, number of rows and number of mines.

4.JPG

5.JPG

Then create within this node the following attributes:

Attribute name Type Default value
COLUMNS I 15
ROWS I 15
MINES I 20

6.JPG

Ok, go to the layout tab and create a new Group for show these settings:

7.JPG

Create now an Input Field with its Label for show the field ‘Columns’, and create the binding with the context:

8.JPG

Repeat the process with the fields ‘Rows’ and ‘Mines’.

Then create a Toolbar with two buttons: NEW_GAME and RESTART. Create also an action for each button:

9.JPG

Create now other Group for the game itself.  And then create in this group a Transparent Container for store the boxes of the game.  Create it with the name BOXES_CONTAINER.

In this transparent container we will create dynamically the boxes of the game. We need to set the property Layout to GridLayout in order to control the number of boxes we want per row depending on the field ‘Columns’ in Settings.

The property colCount represents the number of the grid columns. But this property hasn’t a button for create the binding with the field ‘Columns’. So, how to do it? Later we will change this value dynamically using the method SET_COL_COUNT of the class CL_WD_GRID_LAYOUT.

10.JPG

At this point you should have something like this:

11.JPG

Assistance class

We’re going to create an assistance class for store some texts which we’ll use in the messages. And also some public attributes to be used in an easy way from the methods in the WD component.

Goto SE24 and create a new class:

12.JPG

Set the Superclass CL_WD_COMPONENT_ASSISTANCE:

13.JPG

Create the following text elements:

14.JPG

Create also the following attributes:

15.JPG

Attribute Description
COLUMNS Number of Columns
ROWS Number of Rows
MINES Number of Mines
MAX_BOXES Number of Boxes
BOXES_CHEKED Number of Boxes Checked
BOXES_WITHOUT_MINES Number of Boxes without a Mine
BOX Reference to a context element
MINE_TABLE Table with the numbers of the boxes with a Mine
BOXES_VALIDATED Boxes already validated when a box is used
BOX_PATH First part of the binding path: Value: ‘BOXES.BOX_’

Add the assistance class to the component:

16.JPG

Quick Tip: How to use the assistance class.

When you add an assistance class to a WD component a new attribute called WD_ASSIST is created in each controller.

aaa1.JPG

For get a text element stored in that class you can use the code wizard.  18.JPG

bbb2.JPG

The following code will be generated:

lv_text = wd_assist->if_wd_component_assistance~get_text( ‘001’ ).          

You can use the attributes of the assistance class like this:

wd_assist->rows = 1.

More info: Working with the Assistance Class.

Let’s start adding some code.

The proper place for create new UI elements dynamically is in the method WDDOMODIFYVIEW. This method has a parameter called VIEW type ref to IF_WD_VIEW that we need to use for create the UI elements. But we want to create the UI Elements from the button we’ve created, so a trick for do it is create an attribute in the view:

20.JPG

Then within the method WDDOMODIFYVIEW add the following code to initialize this attribute:

Method WDDOMODIFYVIEW

* Save the parameter ‘View’ in the attribute ‘View_ref’
 
IF first_time EQ ‘X’.

    wd_this->view_ref = view.

  ENDIF.

Now we can create the UI elements from the method we want in this view.

So, go to the tab Methods and create a new method START_GAME. Add a parameter to this method called RESTART, using this parameter we know if we have to start a new game or if we have to restart the current game with the settings saved in the assistance class.

21.JPG

This method set the property colCount of the grid dependind on the field Columns. Then create a root node for store all the boxes nodes. And call to the method Create_Box for creates a context node and a toggle button for each box.

Method START_GAME

    DATA: lo_nd_settings TYPE REF TO if_wd_context_node,
        lo_el_settings
TYPE REF TO if_wd_context_element,
        ls_settings
TYPE wd_this->element_settings.

  DATA: lo_trans_cont TYPE REF TO cl_wd_transparent_container,
        lo_layout
TYPE REF TO cl_wd_layout,
        lo_grid_layout
TYPE REF TO cl_wd_grid_layout.

  DATA: lr_context_info TYPE REF TO if_wd_context_node_info,
        lr_mines_info
TYPE REF TO if_wd_context_node_info.

  DATA: lv_boxes TYPE numc3.

  CONSTANTS: c_boxes TYPE string VALUE ‘BOXES’.

  DATA: lo_api_controller   TYPE REF TO if_wd_controller,
        lo_message_manager 
TYPE REF TO if_wd_message_manager,
        lv_msg             
TYPE string.

* Get the message manager; (Use the code wizard)
  lo_api_controller ?= wd_this->wd_get_api( ).
 
CALL METHOD lo_api_controller->get_message_manager
    RECEIVING
      message_manager = lo_message_manager.

* Read settings;
  lo_nd_settings = wd_context->get_child_node( name = wd_this->wdctx_settings ).
  lo_el_settings = lo_nd_settings->get_element( ).

* Get the transparent container where we’ll create the Boxes
  lo_trans_cont ?= wd_this->view_ref->get_element(
‘BOXES_CONTAINER’ ).

* New game;
 
IF restart EQ space.

*   Read the settings:
    lo_el_settings->get_static_attributes(
     
IMPORTING
        static_attributes = ls_settings ).

*   Get the layot data:
   
CALL METHOD lo_trans_cont->get_layout
      RECEIVING
        the_layout = lo_layout.
    lo_grid_layout ?= lo_layout.

*   Set the column count to the value filled in the settings:
   
CALL METHOD lo_grid_layout->set_col_count
     
EXPORTING
       
value = ls_settings-columns.

*   Save the settings in the assistance class attributes:
    wd_assist->rows = ls_settings-
rows.
    wd_assist->columns = ls_settings-columns.
    wd_assist->mines = ls_settings-mines.
    wd_assist->max_boxes = ls_settings-columns * ls_settings-
rows.
    wd_assist->boxes_without_mines = wd_assist->max_boxes – ls_settings-mines.


*   Validations;

*   Number of mines exceeds the number of boxes ?
   
IF ls_settings-mines GT wd_assist->max_boxes.
      lv_msg = wd_assist->if_wd_component_assistance~get_text(
‘003’ ).
     
CALL METHOD lo_message_manager->report_error_message
       
EXPORTING
          message_text = lv_msg.
     
RETURN.
   
ENDIF.

*   Dimensions exceeded ?
   
IF wd_assist->rows GT 50 OR wd_assist->columns GT 50.
      lv_msg = wd_assist->if_wd_component_assistance~get_text(
‘004’ ).
     
CALL METHOD lo_message_manager->report_error_message
       
EXPORTING
          message_text = lv_msg.
     
RETURN.

    ENDIF.
*    Max num of boxes exceeded
?
   
IF wd_assist->max_boxes GT 1000.

      CALL METHOD lo_message_manager->report_error_message
       
EXPORTING
          message_text = ‘Max number of boxes exceeded: Max 1000’.
     
RETURN.
   
ENDIF.



*   Fill the table with the numbers of the boxes which contain a mine:
    wd_this->fill_mine_table( ).

  ELSE. “Restart ?

*  If we are restarting the game read the settings stored in the assistence class:
    ls_settings-
rows =  wd_assist->rows.
    ls_settings-columns = wd_assist->columns.
    ls_settings-mines = wd_assist->mines.
    lo_el_settings->set_static_attributes(
      
EXPORTING
         static_attributes = ls_settings ).
 
ENDIF.

  CLEAR: wd_assist->boxes_cheked.
* Remove all the UI Toggle buttons created within the

* transparent container in previous games:
 
CALL METHOD lo_trans_cont->remove_all_children.


* Get meta data info of root context node
  lr_context_info = wd_context->get_node_info( ).

* Remove the nodes created in previous games;
 
DATA lo_nd_mines TYPE REF TO if_wd_context_node.
 
TRY.
      lo_nd_mines = wd_context->get_child_node( name = c_boxes ).
   
CATCH cx_wd_context.
 
ENDTRY.

* For the first game lo_nd_mines will be empty
 
IF lo_nd_mines IS NOT INITIAL.

*   Removing the main root node we are removing also all its childs:
   
CALL METHOD lr_context_info->remove_child_node
     
EXPORTING
        name = c_boxes.
 
ENDIF.

* Create a main root node for all the boxes;
 
CALL METHOD lr_context_info->add_new_child_node
   
EXPORTING
      name                         = c_boxes
      is_static                    = abap_false
      is_mandatory                 = abap_true
      is_mandatory_selection       = abap_false
      is_multiple                  = abap_false
      is_multiple_selection        = abap_true
      is_singleton                 = abap_true
      is_initialize_lead_selection = abap_true
    RECEIVING
      child_node_info              = lr_mines_info.


* Create the boxes: Context nodes and UI Elements;
 
DO wd_assist->max_boxes TIMES.

    ADD 1 TO lv_boxes.

    wd_this->create_box(
      io_mines_info = lr_mines_info
      io_trans_cont =  lo_trans_cont
      num_box = lv_boxes ).

  ENDDO.

The method FILL_MINE_TABLE fills the table WD_ASSIST->MINE_TABLE with the number of the boxes that contain a mine.

Method FILL_MINE_TABLE

DATA: lv_number TYPE numc3,
        lv_int   
TYPE int4.

  REFRESH: wd_assist->mine_table.

  DO wd_assist->mines TIMES.

    DO.
     
CALL FUNCTION ‘QF05_RANDOM_INTEGER’
       
EXPORTING
          ran_int_max   = wd_assist->max_boxes
          ran_int_min   =
1
       
IMPORTING
          ran_int       = lv_int
       
EXCEPTIONS
          invalid_input =
1
         
OTHERS        = 2.
      lv_number = lv_int.
     
READ TABLE wd_assist->mine_table WITH KEY num = lv_number
          
TRANSPORTING NO FIELDS.
     
IF sy-subrc EQ 0.
       
CONTINUE.
     
ELSE.
       
APPEND lv_number TO wd_assist->mine_table.
       
EXIT.
     
ENDIF.

    ENDDO.

  ENDDO.

  SORT wd_assist->mine_table.

The method CREATE_BOX create a new context element as child of the ‘root’ context node ‘BOXES’ and then create a new Toggle Button creating a binding with the just created context node.

This method has the following parameters:

22.JPG

Method CREATE_BOX

    DATA: lr_mine_info TYPE REF TO if_wd_context_node_info,
        lr_mine_no
TYPE REF TO if_wd_context_node_info,
        lo_button
TYPE REF TO cl_wd_toggle_button,
        lo_grid_data
TYPE REF TO cl_wd_grid_data,
        lo_nd_mine
TYPE REF TO if_wd_context_node,
        lo_el_mine
TYPE REF TO if_wd_context_element,
        ls_mine
TYPE zzmine,
        lv_path     
TYPE string.

  DATA: lv_checked TYPE string,
        lv_enabled
TYPE string,
        lv_text   
TYPE string,
        lv_image  
TYPE string,
        lv_name   
TYPE string.

   TYPE-POOLS: icon.

* Add a new node:
 
CONCATENATE ‘BOX_’ num_box INTO lv_name.
 
CALL METHOD io_mines_info->add_new_child_node
   
EXPORTING
      static_element_type          =
‘ZZMINE’
      name                         = lv_name
      is_mandatory                 = abap_true
      is_static                    = abap_false
      is_mandatory_selection       = abap_false
      is_multiple                  = abap_false
      is_multiple_selection        = abap_true
      is_singleton                 = abap_true
      is_initialize_lead_selection = abap_true
    RECEIVING
      child_node_info              = lr_mine_info.

* Create the path for the bindings;
 
CONCATENATE wd_assist->box_path num_box ‘.CHECKED’
        
INTO lv_checked.
 
CONCATENATE wd_assist->box_path num_box ‘.TEXT’
        
INTO lv_text.
 
CONCATENATE wd_assist->box_path num_box ‘.ICON’
        
INTO lv_image.

* Bind the property “Enabled” with the inverse of the property Checked

* With this you can only use the button one time.
 
CONCATENATE wd_assist->box_path num_box ‘.CHECKED:NOT’
        
INTO lv_enabled.

* Create a new toggle button and do the binding with the node;
 
CALL METHOD cl_wd_toggle_button=>new_toggle_button
   
EXPORTING
     
id                = lv_name
      bind_checked      = lv_checked
      bind_enabled      = lv_enabled
      bind_text         = lv_text
      bind_image_source = lv_image
      on_toggle         =
‘TOGGLE_BOX’
      width             =
’20px’
    RECEIVING
     
control           = lo_button.

* New grid data element:
  lo_grid_data = cl_wd_grid_data=>new_grid_data( element = lo_button ).

* Add the button to the transparent container MINES_CONTAINER
  io_trans_cont->add_child( lo_button ).

We are setting the action TOGGLE_BOX for the event ON_TOGGLE. We need to create this action, by the moment without code.

We are using the static element type ZZMINE. We need to create it, so go to SE11 and create it with the following fields:

23.JPG

We need to call to this method from the actions NEW_GAME and RESTART:

Action NEW_GAME

wd_this->start_game( ).

Action RESTART

wd_this->start_game( restart = ‘X’ ).

We are going to do the first test to see if everything works properly. First we need to create the Webdynpro Application:

24.JPG

Now do a quick test:

25.JPG

Try to create some games with different amount of boxes:

26.JPG

Context Menus

We are going to create a context menu with two options for mark the boxes as ‘Mine’ or clear this mark.

Go to the layout tab and create a context menu called MENU. Then insert in this menu two menu options. Create also two actions for these options: MARK_AS_MINE and CLEAR_MARK.

27.JPG

28.JPG

We’re going to active these options only when the originator will be a toggle button.

The option MARK_AS_MINE will be enabled when the toggle button is unchecked and the button hasn’t an icon assigned.

The option CLEAR_MARK will be enabled when the toggle button is unchecked and the button has an icon assigned.

For do it we need to add some code to the method WDDOONCONTEXTMENU.

This method has three parameters:

29.JPG

The parameter CONTEXT_MENU_EVENT contains the originator element. With the parameter CONTEXT_MENU_MANAGER we can obtain the object MENU that we need to return.

We haven’t the originator element reference within the actions assigned to the Menu Options, so we are going to save this reference in the attribute BOX of the assistance class.

Method WDDOONCONTEXTMENU

  DATA: lv_node      TYPE string,
        lv_subnode  
TYPE string,
        lv_attribute
TYPE string,
        lo_mine     
TYPE REF TO cl_wd_toggle_button,
        lo_menu_item
TYPE REF TO cl_wd_menu_action_item,
        lv_path     
TYPE string.

  DATA: lo_nd_mine TYPE REF TO if_wd_context_node,
        lo_el_mine
TYPE REF TO if_wd_context_element,
        ls_mine
TYPE zzmine.
* Get the originator toggle button
 
TRY.
      lo_mine ?= context_menu_event->originator.

    CATCH cx_sy_move_cast_error.

*    IF is not a button exit the method;
     
RETURN.
 
ENDTRY.

* Get the path of the primary property biding;
 
CALL METHOD lo_mine->bound__primary_property
    RECEIVING
      path = lv_path.

* Obtain the path to the node;
 
SPLIT lv_path AT ‘.’ INTO lv_node lv_subnode lv_attribute.
 
CONCATENATE lv_node lv_subnode INTO lv_path SEPARATED BY ‘.’.
* Get the data of this node;
  lo_nd_mine = wd_context->path_get_node( path = lv_path ).

* Save the element in the attribute mine of this view

* because in the actions CLEAR_MARK and MARK_AS_MINE we haven’t* this reference:
  wd_assist->box = lo_nd_mine->get_element( ).
  wd_assist->box->get_static_attributes(
   
IMPORTING
      static_attributes = ls_mine ).

* If it’s checked: Exit the method;
 
CHECK ls_mine-checked IS INITIAL.

  menu = context_menu_manager->get_context_menu( ‘MENU’ ).

* If haven’t an icon assigned: Active only the option: MARK_AS_MINE.
  lo_menu_item ?= menu->get_item(
id = ‘MARK_AS_MINE’ ).
 
IF ls_mine-icon EQ SPACE.
    lo_menu_item->set_enabled( abap_true ).
 
ELSE.
    lo_menu_item->set_enabled( abap_false ).
 
ENDIF.


* IF have an icon assigned: Active only the option CLEAR_MARK.
  lo_menu_item ?= menu->get_item(
id = ‘CLEAR_MARK’ ).
 
IF ls_mine-icon EQ SPACE.
    lo_menu_item->set_enabled( abap_false ).
 
ElSE.
    lo_menu_item->set_enabled( abap_true ).
 
ENDIF.

Now we need to add some code to the actions of these buttons:

Action MARK_AS_MINE

DATA: ls_mine TYPE zzmine.

  TYPE-POOLS: icon.

  wd_assist->box->get_static_attributes(
    IMPORTING
      static_attributes = ls_mine ).

  ls_mine-icon = icon_led_green.

  wd_assist->box->set_static_attributes(
    EXPORTING
      static_attributes = ls_mine ).

Action CLEAR_MARK

DATA: ls_mine TYPE zzmine.

  wd_assist->box->get_static_attributes(
    IMPORTING
      static_attributes = ls_mine ).

  ls_mine-icon = SPACE.

  wd_assist->box->set_static_attributes(
    EXPORTING
      static_attributes = ls_mine ).

Do another test and try if works fine:

30.JPG

Adding some logic to the game

The logic of the game is really easy:

– –     – When a box is checked the action TOGGLE_BOX is triggered.

– –     – When a box is checked we validate if contains a Mine reading the table WD_ASSIST->MINE_TABLE. If has a Mine the game is finished: You lose!

–        – If doesn’t contain a Mine then we call the method CHECK_BOX.

–        – The method CHECK_BOX first of all validates if the number of boxes checked (WD_ASSIST->BOXES_CHEKED) is equal to the number of boxes without Mines (WD_ASSIST->BOXES_WITHOUT_MINES), if yes: game finished: You win!

–         – If not, counts the number of neighbors boxes that contain a Mine. If this number is not equal to zero then we print this number in the box and leave the method.

–        – If the number of neighbors’ boxes with a mine is zero then we call recursively to this method with all the neighbors of this box.

Know the number of the neighbors boxes is easy:

31.JPG

Add the following code to the action assigned to the toggle buttons:

Action TOGGLE_BOX

DATA: lo_api_controller  TYPE REF TO if_wd_controller,
        lo_message_manager
TYPE REF TO if_wd_message_manager,
        lv_msg
TYPE string.

  DATA: lv_id   TYPE string,
        lv_path
TYPE string,
        lv_mine
TYPE numc3,
        lo_toggle
TYPE REF TO cl_wd_toggle_button.

  DATA: lo_nd_mine TYPE REF TO if_wd_context_node,
        lo_el_mine
TYPE REF TO if_wd_context_element,
        ls_mine
TYPE zzmine.

  DATA: lv_node TYPE string,
        lv_subnode
TYPE string,
        lv_attribute
TYPE string,
        lv_name
TYPE string,
        lv_num
TYPE numc3.

  TYPE-POOLS: icon.
* get message manager
  lo_api_controller ?= wd_this->wd_get_api( ).
 
CALL METHOD lo_api_controller->get_message_manager
    RECEIVING
      message_manager = lo_message_manager.

* Obtain the box’s name:
  lv_id = wdevent->get_string(
‘ID’ ).
* Obtain the UI element:
  lo_toggle ?= wd_this->view_ref->get_element( lv_id ).
 
CALL METHOD lo_toggle->bound__primary_property
    RECEIVING
      path = lv_path.

* Read the content of the box;
 
SPLIT lv_path AT ‘.’ INTO lv_node lv_subnode lv_attribute.

* Is a mine?
 
SPLIT lv_subnode AT ‘_’ INTO lv_name lv_mine.
 
READ TABLE wd_assist->mine_table WITH KEY num = lv_mine
      
TRANSPORTING NO FIELDS.
 
IF sy-subrc EQ 0.

*   Display a message: You lose !
    lv_msg = wd_assist->if_wd_component_assistance~get_text(
‘002’ ).
   
CALL METHOD lo_message_manager->report_error_message
     
EXPORTING
        message_text = lv_msg.
*   Show all the mines in red:
    wd_this->show_mines(
icon = icon_led_red ).
   
RETURN.
 
ENDIF.


* If haven’t a mine, call the method check_box
* The method will be called recursively to check the neighboring boxes.

* The table wd_assist->boxes_validated have the number of the boxes

*  that are already validated:
 
REFRESH wd_assist->boxes_validated.
 
SPLIT lv_subnode AT ‘_’ INTO lv_subnode lv_num.
  wd_this->check_box( box_num = lv_num first_time =
‘X’ ).

The method CHECK_BOX will be called recursively:

Method CHECK_BOX

TYPE-POOLS: icon.

  DATA: lo_nd_settings TYPE REF TO if_wd_context_node,
        lo_el_settings
TYPE REF TO if_wd_context_element,
        ls_settings
TYPE wd_this->element_settings.

  DATA: lo_nd_mine TYPE REF TO if_wd_context_node,
        lo_el_mine
TYPE REF TO if_wd_context_element,
        ls_mine
TYPE zzmine.

  DATA: lv_id TYPE string,
        lv_num
TYPE numc3,
        lv_int
TYPE i,
        lv_row
TYPE i,
        lv_column
TYPE i,
        lv_mines
TYPE n,
        lv_path
TYPE string.

  DATA: lo_api_controller  TYPE REF TO if_wd_controller,
        lo_message_manager
TYPE REF TO if_wd_message_manager,
        lv_msg            
TYPE string.
* Get the message manager;
  lo_api_controller ?= wd_this->wd_get_api( ).
 
CALL METHOD lo_api_controller->get_message_manager
    RECEIVING
      message_manager = lo_message_manager.
* Check if the box has already been validated;
 
READ TABLE wd_assist->boxes_validated WITH KEY num = box_num
      
TRANSPORTING NO FIELDS.
 
IF sy-subrc EQ 0.
   
RETURN. “Exit the method
 
ELSE.
   
APPEND lv_int TO wd_assist->boxes_validated.
 
ENDIF.

* Settings:
  lo_nd_settings = wd_context->get_child_node( name = wd_this->wdctx_settings ).
  lo_el_settings = lo_nd_settings->get_element( ).
  lo_el_settings->get_static_attributes(
   
IMPORTING
      static_attributes = ls_settings ).

* Check if is checked;
 
CONCATENATE zcl_test_ms_assistence=>box_path box_num INTO lv_path.
  lo_nd_mine = wd_context->path_get_node( path = lv_path ).
  lo_el_mine = lo_nd_mine->get_element( ).
  lo_el_mine->get_static_attributes(
   
IMPORTING
      static_attributes = ls_mine ).
 
IF ls_mine-checked EQ ‘X’ AND first_time EQ space.
   
RETURN.
 
ENDIF.

* Add 1 to the number of boxes checked
  ADD 1 TO wd_assist->boxes_cheked.


* If the number of boxes chequed is equal to the boxes without mines:

* then: You win !
 
IF wd_assist->boxes_cheked EQ wd_assist->boxes_without_mines.

*   Display a message: You win !
    lv_msg = wd_assist->if_wd_component_assistance~get_text(
‘001’ ).
   
CALL METHOD lo_message_manager->report_success
     
EXPORTING
        message_text = lv_msg.

*   Show all the mines in green:
    wd_this->show_mines(
icon = icon_led_green ).
   
RETURN.
 
ENDIF.


* Check if the neighbors boxes have a mine.

* We have stored the number of boxes with a mine

* in the attribute mine_table of the assistence class


* Number of column of the current box
  lv_column = box_num
MOD wd_assist->columns.
 
IF lv_column EQ 0.
    lv_column = wd_assist->columns.
 
ENDIF.

* Number of row of the current box
  lv_row =
CEIL( box_num / wd_assist->columns ).

* Check the upper left box:
 
IF lv_row GT 1 AND lv_column GT 1.
    lv_int = box_num – ls_settings-columns –
1.
   
IF lv_int IS NOT INITIAL.
     
READ TABLE wd_assist->mine_table WITH KEY num = lv_int
        
TRANSPORTING NO FIELDS.
     
IF sy-subrc EQ 0.
       
ADD 1 TO lv_mines.
     
ENDIF.
   
ENDIF.
 
ENDIF.

* Check the upper box
 
IF lv_row GT 1.
    lv_int = box_num – ls_settings-columns.
   
IF lv_int IS NOT INITIAL.
     
READ TABLE wd_assist->mine_table WITH KEY num = lv_int
        
TRANSPORTING NO FIELDS.
     
IF sy-subrc EQ 0.
       
ADD 1 TO lv_mines.
     
ENDIF.
   
ENDIF.
 
ENDIF.

* Check the upper right box
 
IF lv_row GT 1 AND lv_column LT wd_assist->columns.
    lv_int = box_num – ls_settings-columns +
1.
   
IF lv_int IS NOT INITIAL.
     
READ TABLE wd_assist->mine_table WITH KEY num = lv_int
        
TRANSPORTING NO FIELDS.
     
IF sy-subrc EQ 0.
       
ADD 1 TO lv_mines.
     
ENDIF.
   
ENDIF.
 
ENDIF.

* Check the left box
 
IF lv_column GT 1.
    lv_int = box_num –
1.
   
IF lv_int IS NOT INITIAL.
     
READ TABLE wd_assist->mine_table WITH KEY num = lv_int
        
TRANSPORTING NO FIELDS.
     
IF sy-subrc EQ 0.
       
ADD 1 TO lv_mines.
     
ENDIF.
   
ENDIF.
 
ENDIF.

* Check the right box
 
IF lv_column LT wd_assist->columns.
    lv_int = box_num +
1.
   
IF lv_int LE wd_assist->max_boxes.
     
READ TABLE wd_assist->mine_table WITH KEY num = lv_int
        
TRANSPORTING NO FIELDS.
     
IF sy-subrc EQ 0.
       
ADD 1 TO lv_mines.
     
ENDIF.
   
ENDIF.
 
ENDIF.

* Check the lower left box
 
IF lv_column GT 1 AND lv_row LT wd_assist->rows.
    lv_int = box_num + ls_settings-columns –
1.
   
IF lv_int LT wd_assist->max_boxes.
     
READ TABLE wd_assist->mine_table WITH KEY num = lv_int
        
TRANSPORTING NO FIELDS.
     
IF sy-subrc EQ 0.
       
ADD 1 TO lv_mines.
     
ENDIF.
   
ENDIF.
 
ENDIF.

* Check the lower box
 
IF lv_row LT wd_assist->rows.
    lv_int = box_num + ls_settings-columns.
   
IF lv_int LT wd_assist->max_boxes.
     
READ TABLE wd_assist->mine_table WITH KEY num = lv_int
        
TRANSPORTING NO FIELDS.
     
IF sy-subrc EQ 0.
       
ADD 1 TO lv_mines.
     
ENDIF.
   
ENDIF.
 
ENDIF.

* Check the lower right box
 
IF lv_row LT wd_assist->rows AND lv_column LT wd_assist->columns.
    lv_int = box_num + ls_settings-columns +
1.
   
IF lv_int LT wd_assist->max_boxes.
     
READ TABLE wd_assist->mine_table WITH KEY num = lv_int
        
TRANSPORTING NO FIELDS.
     
IF sy-subrc EQ 0.
       
ADD 1 TO lv_mines.
     
ENDIF.
   
ENDIF.
 
ENDIF.


* If the number of the neighbors boxes with a mine is greater than 0

* print this number in this box and exit the method:
 
IF lv_mines GT 0.

    ls_mine-text = lv_mines.
    ls_mine-checked =
‘X’.
    ls_mine-
icon = space.
    lo_el_mine->set_static_attributes(
     
EXPORTING
       static_attributes = ls_mine ).
   
RETURN.
 
ENDIF.


* If the number of neighbors boxes with a mine is 0,

* then mark the mine as checked and continue validating

* the neighbors of this box.
  ls_mine-checked = ‘X’.
  ls_mine-
icon = space.
  lo_el_mine->set_static_attributes(
   
EXPORTING
     static_attributes = ls_mine ).

* Validate the neighbors boxes:
* Check the upper left box:
 
IF lv_row GT 1 AND lv_column GT 1.
    lv_int = box_num – ls_settings-columns –
1.
   
IF lv_int IS NOT INITIAL.
      lv_num = lv_int.
      wd_this->check_box( box_num = lv_num first_time = space ).
   
ENDIF.
 
ENDIF.

* Check the upper box
 
IF lv_row GT 1.
    lv_int = box_num – ls_settings-columns.
   
IF lv_int IS NOT INITIAL.
      lv_num = lv_int.
      wd_this->check_box( box_num = lv_num first_time = space ).
   
ENDIF.
 
ENDIF.

* Check the upper right box
 
IF lv_row GT 1 AND lv_column LT wd_assist->columns.
    lv_int = box_num – ls_settings-columns +
1.
   
IF lv_int IS NOT INITIAL.
      lv_num = lv_int.
      wd_this->check_box( box_num = lv_num first_time = space ).
   
ENDIF.
 
ENDIF.

* Check the left box
 
IF lv_column GT 1.
    lv_int = box_num –
1.
   
IF lv_int IS NOT INITIAL.
      lv_num = lv_int.
      wd_this->check_box( box_num = lv_num first_time = space ).
   
ENDIF.
 
ENDIF.

* Check the right box
 
IF lv_column LT wd_assist->columns.
    lv_int = box_num +
1.
   
IF lv_int LE wd_assist->max_boxes.
      lv_num = lv_int.
      wd_this->check_box( box_num = lv_num first_time = space ).
   
ENDIF.
 
ENDIF.

* Check the lower left box
 
IF lv_column GT 1 AND lv_row LT wd_assist->rows.
    lv_int = box_num + ls_settings-columns –
1.
   
IF lv_int LE wd_assist->max_boxes.
      lv_num = lv_int.
      wd_this->check_box( box_num = lv_num first_time = space ).
   
ENDIF.
 
ENDIF.


* Check the lower box
 
IF lv_row LT wd_assist->rows.
    lv_int = box_num + ls_settings-columns.
   
IF lv_int LE wd_assist->max_boxes.
      lv_num = lv_int.
      wd_this->check_box( box_num = lv_num first_time = space ).
   
ENDIF.
 
ENDIF.


* Check the lower right box
 
IF lv_column LT wd_assist->columns AND lv_row LT wd_assist->rows.
    lv_int = box_num + ls_settings-columns +
1.
   
IF lv_int LE wd_assist->max_boxes.
      lv_num = lv_int.
      wd_this->check_box( box_num = lv_num first_time = space ).
   
ENDIF.
 
ENDIF.

ox
 
IF lv_column GT 1 AND lv_row LT wd_assist->rows.
    lv_int = box_num + ls_settings-columns –
1.
   
IF lv_int LE wd_assist->max_boxes.
      lv_num = lv_int.
      wd_this->check_box( box_num = lv_num first_time = space ).
   
ENDIF.
 
ENDIF.

Create other method for show all the mines:

SHOW_MINES

DATA: lo_nd_mine TYPE REF TO if_wd_context_node,
        lo_el_mine
TYPE REF TO if_wd_context_element,
        ls_mine
TYPE zzmine,
        lv_path
TYPE string,
        lv_mine
TYPE numc3.
*   Show all the mines:
   
LOOP AT wd_assist->mine_table INTO lv_mine.
     
CONCATENATE ‘BOXES.BOX_’ lv_mine INTO lv_path.
      lo_nd_mine = wd_context->path_get_node( path = lv_path ).
      lo_el_mine = lo_nd_mine->get_element( ).
      lo_el_mine->get_static_attributes(
       
IMPORTING
          static_attributes = ls_mine ).
      ls_mine-
icon = icon.
      ls_mine-checked =
‘X’.
      lo_el_mine->set_static_attributes(
      
EXPORTING
          static_attributes = ls_mine ).
   
ENDLOOP.

Result:

Related content:

http://help.sap.com/saphelp_nw70/helpdata/en/af/cb744176cb127de10000000a155106/content.htm

http://213.41.80.15/SAP_ELearning/OKEC/nav/content/011000358700001936642005e.pdf

http://www.sdn.sap.com/irj/scn/index?rid=/library/uuid/201ddd3b-b4ce-2b10-8883-880ae8147f89&overridelayout=true

To report this post you need to login first.

6 Comments

You must be Logged on to comment or reply to a post.

  1. Uday Gubbala

    Hi Ricardo,

    Great effort! 🙂 Nice way of making learning fun. The application is even of a reasonably good complexity level which helps give the budding developers a good insight into real time WDA development. 5 stars from me & look forward to a “Super Mario” from your end! 😛

    Regards,

    Uday

    (0) 
  2. SAYAN SUBHRA JANA

    Hi Ricardo,

    Great Job. It was a great learning.

    I tried replicating but faced few issues:

    1. In method START_GAME, I faced a type mismatch error at the following line resulting in a dump

        lo_grid_layout ?= lo_layout.

    So I tried with the following code:

          CALL METHOD cl_wd_grid_layout=>new_grid_layout
          EXPORTING
            col_count              = ls_settings-columns
            container              = lo_trans_cont
          RECEIVING
            control                = lo_grid_layout.

    Its working fine.

    2.     If there are more than 1000 boxes we are getting a dump, BOX_000 to BOX_999 are allowed since NUMC3 is taken as the datatype of importing parameter NUM_BOX.

    Regards,

    Sayan

    (0) 
    1. Ricardo Romero Mata Post author

      Hi Sayan, thanks for warn me about these issues.

      1. Is strange, for me is working fine with my code. You need to set the layout type to “Grid Layout” to the transparent container in design time.

      2. You are right, I’ve added a new  validation with an error message in the code of method START_GAME if the number of boxes is greater than 1000.

      (0) 

Leave a Reply