Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 

Hi,

In this post I'll share with you the N Queens Algorithm brought to the ABAP language. I think this is a good exercise when it comes to refreshing our algorithmic capabilities.


*&---------------------------------------------------------------------*
*& Report  Z_8QUEENS
*&         Up to 10 x 10
*&---------------------------------------------------------------------*
*& Rubén Mircin
*&---------------------------------------------------------------------*
REPORT  Z_8QUEENS.
TYPES: BEGIN OF gty_matrix,
          1  TYPE c,
          2  TYPE c,
          3  TYPE c,
          4  TYPE c,
          5  TYPE c,
          6  TYPE c,
          7  TYPE c,
          8  TYPE c,
          9  TYPE c,
          10 TYPE c,
        END OF gty_matrix,
        gty_t_matrix TYPE STANDARD TABLE OF gty_matrix INITIAL SIZE 8.
DATA: gt_matrix TYPE gty_t_matrix,
       gs_matrix TYPE gty_matrix,
       gv_count  TYPE i VALUE 0,
       gv_solut  TYPE i VALUE 0.
SELECTION-SCREEN BEGIN OF BLOCK b01 WITH FRAME TITLE text-b01.
PARAMETERS: p_number TYPE i OBLIGATORY DEFAULT 8.
SELECTION-SCREEN END OF BLOCK b01.
" Filling empty table
START-OF-SELECTION.
   DO p_number TIMES.
     APPEND gs_matrix TO gt_matrix.
   ENDDO.
" Recursive Function
   PERFORM fill_matrix USING gv_count 1 1 CHANGING gt_matrix.
*&---------------------------------------------------------------------*
*&      Form  FILL_MATRIX
*----------------------------------------------------------------------*
FORM fill_matrix  USING    p_count TYPE i
                            p_i     TYPE i
                            p_j     TYPE i
                   CHANGING p_matrix TYPE gty_t_matrix.
   DATA: lv_i      TYPE i,
         lv_j      TYPE i,
         lv_result TYPE c LENGTH 1,
         lt_matrix TYPE gty_t_matrix,
         lv_count  TYPE i,
         lv_value  TYPE c.
   lt_matrix[] = p_matrix[].
   lv_count = p_count.
   lv_i = p_i.
   lv_j = p_j.
   IF lv_count EQ p_number.
     RETURN.
   ENDIF.
   WHILE lv_i LE p_number.
     WHILE lv_j LE p_number.
       CLEAR lv_result.
       PERFORM check_position USING lv_i lv_j CHANGING lv_result lt_matrix.
       IF lv_result NE 'X'.
         MOVE 'X' TO lv_value.
         PERFORM get_position USING lv_i lv_j 'U' CHANGING lv_value lt_matrix.
         ADD 1 TO lv_count.
         IF lv_count EQ p_number.
           PERFORM show_matrix USING lt_matrix.
         ELSE.
           PERFORM fill_matrix USING lv_count lv_i lv_j CHANGING lt_matrix.
         ENDIF.
         lv_value = space.
         PERFORM get_position USING lv_i lv_j 'U' CHANGING lv_value lt_matrix.
         SUBTRACT 1 FROM lv_count.
       ENDIF.
       ADD 1 TO lv_j.
     ENDWHILE.
     ADD 1 TO lv_i.
     lv_j = 1.
   ENDWHILE.
ENDFORM.                    " FILL_MATRIX
*&---------------------------------------------------------------------*
*&      Form  CHECK_POSITION
*&---------------------------------------------------------------------*
FORM check_position  USING value(p_i)  TYPE i
                            value(p_j)  TYPE i
                      CHANGING p_result TYPE c
                               p_matrix TYPE gty_t_matrix.
   DATA: lv_i TYPE i,
         lv_j TYPE i.
   lv_i = p_i.
   lv_j = p_j.
   PERFORM get_position USING lv_i lv_j 'R' CHANGING p_result p_matrix.
   CHECK p_result NE 'X'.
   PERFORM check_horizontal USING lv_i lv_j CHANGING p_result p_matrix.
   CHECK p_result NE 'X'.
   PERFORM check_vertical USING lv_i lv_j CHANGING p_result p_matrix.
   CHECK p_result NE 'X'.
   PERFORM check_diagonals USING lv_i lv_j CHANGING p_result p_matrix.
ENDFORM.                    " CHECK_POSITION
*&---------------------------------------------------------------------*
*&      Form  GET_POSITION
*&---------------------------------------------------------------------*
FORM get_position  USING value(p_i)      TYPE i
                          value(p_j)      TYPE i
                          value(p_action) TYPE c
                       CHANGING p_result  TYPE c
                                p_matrix  TYPE gty_t_matrix.
   FIELD-SYMBOLS: <fs_lmatrix> TYPE gty_matrix,
                  <fs_lfield> TYPE any.
   READ TABLE p_matrix ASSIGNING <fs_lmatrix> INDEX p_i.
   ASSIGN COMPONENT p_j OF STRUCTURE <fs_lmatrix> TO <fs_lfield>.
   CASE p_action.
     WHEN 'U'.
       <fs_lfield> = p_result.
     WHEN 'R'.
       p_result = <fs_lfield>.
     WHEN OTHERS.
   ENDCASE.
ENDFORM.                    " GET_POSITION
*&---------------------------------------------------------------------*
*&      Form  CHECK_HORIZONTAL
*&---------------------------------------------------------------------*
FORM check_horizontal  USING value(p_i)      TYPE i
                              value(p_j)      TYPE i
                           CHANGING p_result  TYPE c
                                    p_matrix  TYPE gty_t_matrix.
   DATA: lv_j TYPE i,
         ls_matrix TYPE gty_matrix.
   FIELD-SYMBOLS <fs> TYPE c.
   lv_j = 1.
   READ TABLE p_matrix INTO ls_matrix INDEX p_i.
   WHILE lv_j LE p_number.
     ASSIGN COMPONENT lv_j OF STRUCTURE ls_matrix TO <fs>.
     IF <fs> EQ 'X'.
       p_result = 'X'.
       RETURN.
     ENDIF.
     ADD 1 TO lv_j.
   ENDWHILE.
ENDFORM.                    " CHECK_HORIZONTAL
*&---------------------------------------------------------------------*
*&      Form  CHECK_VERTICAL
*&---------------------------------------------------------------------*
FORM check_vertical  USING value(p_i)      TYPE i
                            value(p_j)      TYPE i
                         CHANGING p_result  TYPE c
                                  p_matrix  TYPE gty_t_matrix.
   DATA: lv_i TYPE i,
         ls_matrix TYPE gty_matrix.
   FIELD-SYMBOLS <fs> TYPE c.
   lv_i = 1.
   WHILE lv_i LE p_number.
     READ TABLE p_matrix INTO ls_matrix INDEX lv_i.
     ASSIGN COMPONENT p_j OF STRUCTURE ls_matrix TO <fs>.
     IF <fs> EQ 'X'.
       p_result = 'X'.
       RETURN.
     ENDIF.
     ADD 1 TO lv_i.
   ENDWHILE.
ENDFORM.                    " CHECK_VERTICAL
*&---------------------------------------------------------------------*
*&      Form  CHECK_DIAGONALS
*&---------------------------------------------------------------------*
FORM check_diagonals  USING value(p_i)      TYPE i
                             value(p_j)      TYPE i
                          CHANGING p_result  TYPE c
                                   p_matrix  TYPE gty_t_matrix.
   DATA: lv_dx TYPE i,
         lv_dy TYPE i.
* I++ J++ (Up Right)
   lv_dx = 1.
   lv_dy = 1.
   PERFORM check_diagonal USING p_i p_j lv_dx lv_dy CHANGING p_result p_matrix.
   CHECK p_result NE 'X'.
* I-- J-- (Left Down)
   lv_dx = -1.
   lv_dy = -1.
   PERFORM check_diagonal USING p_i p_j lv_dx lv_dy CHANGING p_result p_matrix.
   CHECK p_result NE 'X'.
* I++ J-- (Right Down)
   lv_dx = 1.
   lv_dy = -1.
   PERFORM check_diagonal USING p_i p_j lv_dx lv_dy CHANGING p_result p_matrix.
   CHECK p_result NE 'X'.
* I-- J++ (Left Up)
   lv_dx = -1.
   lv_dy = 1.
   PERFORM check_diagonal USING p_i p_j lv_dx lv_dy CHANGING p_result p_matrix.
   CHECK p_result NE 'X'.
ENDFORM.                    " CHECK_DIAGONALS
*&---------------------------------------------------------------------*
*&      Form  CHECK_DIAGONAL
*&---------------------------------------------------------------------*
FORM check_diagonal  USING value(p_i)      TYPE i
                             value(p_j)      TYPE i
                             value(p_dx)      TYPE i
                             value(p_dy)      TYPE i
                          CHANGING p_result  TYPE c
                                   p_matrix  TYPE gty_t_matrix.
   DATA: lv_i TYPE i,
         lv_j TYPE i,
         ls_matrix TYPE gty_matrix.
   FIELD-SYMBOLS <fs> TYPE c.
   lv_i = p_i.
   lv_j = p_j.
   WHILE 1 EQ 1.
     ADD: p_dx TO lv_i, p_dy TO lv_j.
     IF p_dx EQ 1.
       IF lv_i GT p_number. EXIT. ENDIF.
     ELSE.
       IF lv_i LT 1. EXIT. ENDIF.
     ENDIF.
     IF p_dy EQ 1.
       IF lv_j GT p_number. EXIT. ENDIF.
     ELSE.
       IF lv_j LT 1. EXIT. ENDIF.
     ENDIF.
     READ TABLE p_matrix INTO ls_matrix INDEX lv_i.
     ASSIGN COMPONENT lv_j OF STRUCTURE ls_matrix TO <fs>.
     IF <fs> EQ 'X'.
       p_result = 'X'.
       RETURN.
     ENDIF.
   ENDWHILE.
ENDFORM.                    " CHECK_DIAGONAL
*&---------------------------------------------------------------------*
*&      Form  SHOW_MATRIX
*----------------------------------------------------------------------*
FORM show_matrix USING p_matrix TYPE gty_t_matrix.
   DATA: lt_matrix TYPE gty_t_matrix,
         lv_j      TYPE i VALUE 1,
         lv_colum  TYPE string VALUE '-'.
   FIELD-SYMBOLS: <fs_matrix> TYPE gty_matrix,
                  <fs_field>  TYPE c.
*  lt_matrix[] = p_matrix.
*  REPLACE ALL OCCURRENCES OF 'X' IN TABLE lt_matrix WITH '♕' IGNORING CASE IN CHARACTER MODE.
   ADD 1 TO gv_solut.
   WRITE:/ 'Solution: ', gv_solut.
   DO p_number TIMES.
     CONCATENATE lv_colum '----' INTO lv_colum.
   ENDDO.
*  LOOP AT lt_matrix ASSIGNING <fs_matrix>.
   LOOP AT p_matrix ASSIGNING <fs_matrix>.
     IF sy-tabix EQ 1.
       WRITE:/ lv_colum.
     ENDIF.
     WRITE:/ '|'.
     DO p_number TIMES.
       ASSIGN COMPONENT lv_j OF STRUCTURE <fs_matrix> TO <fs_field>.
       IF <fs_field> EQ space.
         WRITE: <fs_field> ,'|'.
       ELSE.
         WRITE: <fs_field> COLOR 2 HOTSPOT ON,'|'.
       ENDIF.
       ADD 1 TO lv_j.
     ENDDO.
     lv_j = 1.
     WRITE: / lv_colum.
   ENDLOOP.
   SKIP 1.
ENDFORM.                    " SHOW_MATRIX

Kind Regards.

Rubén

3 Comments