#!/usr/bin/awk -f
# tested with mawk 1.3.3 on Raspberry Pi 3
#        also GNU awk 3.1.5, busybox 1.21.1 and 1.27.1 on AMD Sempron 2800+
#
function setblocks() {
# key to the algorithm is the representation of a block
# each block is represented by 4 characters in the string "blocks"
# for example, the "BO" block becomes "-BO-"
#
blocks="-BO--XK--DQ--CP--NA--GT--RE--TG--QD--FS--JW--HU--VI--AN--OB--ER--FS--LY--PC--ZM-"
true=1
false=0
}
function found(letter){
#
# the function "found" scans for the letter on the top of a block
# using the pattern "-B", for example, to find a "B",
# returning "true" (or 1) if found
# if not found on the top, look on the bottoms using the pattern "B-"
# again returning "true" if found
# if the letter is found on either top or bottom, the 4 character block is set to "----"
# so that block is unavailable
# finally, if no available copy of letter is found,
# the function returns "false" (0)
position= index(blocks,"-" letter)
if (position > 0)
   {
  blocks = substr(blocks,1,position-1) "----" substr(blocks,position+4)
  return true
   }
position = index(blocks,letter "-")
if (position > 0)
   {blocks = substr(blocks,1,position-3) "----" substr(blocks,position+2)
     return true
    }
return false
}
# awk's BEGIN statement allows for initialization before processing input;
# in this case, initializing the string "blocks"
#
BEGIN{
setblocks()
}
# in awk, the input record is contained in the string variable "$0"
# the main process checks each letter in turn to see if it is on a usable block,
# summing the values returned by "found"
# if the sum equals the number of input characters the word can be spelled with the blocks
# otherwise it is not possible
#
{
nchars=length($0)
possible=false
for (i=1;i<=nchars;i++){
     possible=possible + found(substr($0,i,1))
}
if (possible==nchars) print $0 " is possible"
   else print $0 " is not possible"
setblocks()
}

 and -----------------
#!/usr/bin/awk -f
# tested with mawk 1.3.3 on Raspberry Pi 3
#        also GNU awk 3.1.5, busybox 1.21.1 and 1.27.1 on AMD Sempron 2800+
#
function setblocks() {
#
#  key to the algorithm is the representation of the blocks
# each block is represented by 1 character in the string "tops"
# and by 1 character in the string "bottoms"
#
   tops="BXDCNGRTQFJHVAOEFLPZ"
bottoms="OKQPATEGDSWUINBRSYCM"
true=1
false=0
}
function found(letter){
#
# the function "found" scans first the string "tops" for a letter and
# then the string "bottoms" if the letter is not in "tops"
# if the letter is found, it marks "tops" and "bottoms" to show
# the block is unavailable by changing the letters on the block to "-"
# and returns "true" (1); if the letter is not found
# the function returns "false" (0)
#
position= index(tops,letter)
if (position > 0)
   {
  tops = substr(tops,1,position-1) "-" substr(tops,position+1)
  bottoms = substr(bottoms,1,position-1) "-" substr(bottoms,position+1)
  return true
   }
position = index(bottoms,letter)
if (position > 0)
   {bottoms = substr(bottoms,1,position-1) "-" substr(bottoms,position+1)
    tops = substr(tops,1,position-1) "-" substr(tops,position+1)
     return true
    }
return false
}
# awk's BEGIN statement allows for initialization before processing input;
# in this case, initializing the string "blocks"
#
BEGIN{
setblocks()
}
# in awk, the input record is contained in the string variable "$0"
# the main process checks each letter in turn to see if it is on a usable block,
# summing the values returned by "found"
# if the sum equals the number of input characters the word can be spelled with the blocks
# otherwise it is not possible
#
{
nchars=length($0)
possible=false
for (i=1;i<=nchars;i++){
     possible=possible + found(substr($0,i,1))
}
if (possible==nchars) print $0 " is possible"
   else print $0 " is not possible"
setblocks()
}

"Function to determine if a given word can be spelled using a specific collection of ABC blocks. Each block can only be used once and the function is case-insensitive."


# syntax: GAWK -f SORT_A_LIST_OF_OBJECT_IDENTIFIERS.AWK
#
# sorting:
#   PROCINFO["sorted_in"] is used by GAWK
#   SORTTYPE is used by Thompson Automation's TAWK
#
BEGIN {
    width = 10
    oid_arr[++n] = "1.3.6.1.4.1.11.2.17.19.3.4.0.10"
    oid_arr[++n] = "1.3.6.1.4.1.11.2.17.5.2.0.79"
    oid_arr[++n] = "1.3.6.1.4.1.11.2.17.19.3.4.0.4"
    oid_arr[++n] = "1.3.6.1.4.1.11150.3.4.0.1"
    oid_arr[++n] = "1.3.6.1.4.1.11.2.17.19.3.4.0.1"
    oid_arr[++n] = "1.3.6.1.4.1.11150.3.4.0"
#   oid_arr[++n] = "1.11111111111.1" # un-comment to test error
    for (i=1; i<=n; i++) {
      str = ""
      for (j=1; j<=split(oid_arr[i],arr2,"."); j++) {
        str = sprintf("%s%*s.",str,width,arr2[j])
        if ((leng = length(arr2[j])) > width) {
          printf("error: increase sort key width from %d to %d for entry %s\n",width,leng,oid_arr[i])
          exit(1)
        }
      }
      arr3[str] = ""
    }
    PROCINFO["sorted_in"] = "@ind_str_asc" ; SORTTYPE = 1
    for (i in arr3) {
      str = i
      gsub(/ /,"",str)
      sub(/\.$/,"",str)
      printf("%s\n",str)
    }
    exit(0)
}

sort a list of Object Identifiers (OIDs) in their natural lexicographical order. The OIDs are strings of non-negative integers separated by dots.


Works with: GAWK

BEGIN {
    s="/inet/tcp/256/0/0"
    print strftime() |& s
    close(s)
}

BEGIN {
    s="/inet/tcp/0/localhost/256"
    s |& getline
    print $0
    close(s)
}

The code opens a socket to localhost on port 256, sends the message "hello socket world", and then closes the socket. It does not handle exceptions or errors.


"Generate a sequential count in octal format starting from zero with an increment of one. Each number is printed on a separate line. The program continues to count until it is terminated or the maximum value of the numeric type in use is reached. The code uses the printf command from the C library, supported by the awk extraction and reporting language, to output the counter value in octal."


# syntax: GAWK -f GENERIC_SWAP.AWK
BEGIN {
    printf("%s version %s\n",ARGV[0],PROCINFO["version"])
    foo = 1
    bar = "a"
    printf("\n%s %s\n",foo,bar)
    rc = swap("foo","bar") # ok
    printf("%s %s %s\n",foo,bar,rc?"ok":"ng")
    printf("\n%s %s\n",foo,bar)
    rc = swap("FOO","BAR") # ng
    printf("%s %s %s\n",foo,bar,rc?"ok":"ng")
    exit(0)
}
function swap(a1,a2,  tmp) { # strings or numbers only; no arrays
    if (a1 in SYMTAB && a2 in SYMTAB) {
      if (isarray(SYMTAB[a1]) || isarray(SYMTAB[a2])) {
        return(0)
      }
      tmp = SYMTAB[a1]
      SYMTAB[a1] = SYMTAB[a2]
      SYMTAB[a2] = tmp
      return(1)
    }
    return(0)
}

implement a generic swap function or operator that can interchange the values of two variables or storage places, regardless of their types. The function is designed to work with both statically and dynamically typed languages, with certain limitations based on language semantics and support for parametric polymorphism.


function is_palindro(s)
{
  if ( s == reverse(s) ) return 1
  return 0
}

function is_palindro_r(s)
{
  if ( length(s) < 2 ) return 1
  if ( substr(s, 1, 1) != substr(s, length(s), 1) ) return 0
  return is_palindro_r(substr(s, 2, length(s)-2))
}

BEGIN {
  pal = "ingirumimusnocteetconsumimurigni"
  print is_palindro(pal)
  print is_palindro_r(pal)
}

The code is a program that checks if a given sequence of characters is a palindrome. It supports Unicode characters and also detects inexact palindromes by ignoring white-space, punctuation, and case sensitivity. It uses both non-recursive and recursive methods for string reversal and testing.


$ awk 'BEGIN{print "HOME:"ENVIRON["HOME"],"USER:"ENVIRON["USER"]}'

demonstrate how to retrieve a specific environment variable from a process, list all the environment variables, and assign environment variables to awk variables prior to execution. The code also explains that the ENVIRON array contains the current environment values and highlights common Unix environment variables such as PATH, HOME, and USER.


# syntax: GAWK -f SUDAN_FUNCTION.AWK
BEGIN {
    for (n=0; n<=1; n++) {
      printf("sudan(%d,x,y)\n",n)
      printf("y/x    0   1   2   3   4   5\n")
      printf("%s\n",strdup("-",28))
      for (y=0; y<=6; y++) {
        printf("%2d | ",y)
        for (x=0; x<=5; x++) {
          printf("%3d ",sudan(n,x,y))
        }
        printf("\n")
      }
      printf("\n")
    }
    n=1; x=3; y=3; printf("sudan(%d,%d,%d)=%d\n",n,x,y,sudan(n,x,y))
    n=2; x=1; y=1; printf("sudan(%d,%d,%d)=%d\n",n,x,y,sudan(n,x,y))
    n=2; x=2; y=1; printf("sudan(%d,%d,%d)=%d\n",n,x,y,sudan(n,x,y))
    n=3; x=1; y=1; printf("sudan(%d,%d,%d)=%d\n",n,x,y,sudan(n,x,y))
    exit(0)
}
function sudan(n,x,y) {
    if (n == 0) { return(x+y) }
    if (y == 0) { return(x) }
    return sudan(n-1, sudan(n,x,y-1), sudan(n,x,y-1)+y)
}
function strdup(str,n,  i,new_str) {
    for (i=1; i<=n; i++) {
      new_str = new_str str
    }
    return(new_str)
}

Implement the Sudan function, a non-primitive recursive function. The function takes two arguments, x and y, and returns a value based on the defined recursive rules.


report z_stack.

interface stack.
  methods:
    push
      importing
        new_element      type any
      returning
        value(new_stack) type ref to stack,

    pop
      exporting
        top_element      type any
      returning
        value(new_stack) type ref to stack,

    empty
      returning
        value(is_empty) type abap_bool,

    peek
      exporting
        top_element type any,

    get_size
      returning
        value(size) type int4,

    stringify
      returning
        value(stringified_stack) type string.
endinterface.

class character_stack definition.
  public section.
    interfaces:
      stack.

    methods:
      constructor
        importing
          characters type string optional.

  private section.
    data:
      characters type string.
endclass.

class character_stack implementation.
  method stack~push.
    characters = |{ new_element }{ characters }|.

    new_stack = me.
  endmethod.

  method stack~pop.
    if not me->stack~empty( ).
      top_element = me->characters(1).

      me->characters = me->characters+1.
    endif.

    new_stack = me.
  endmethod.

  method stack~empty.
    is_empty = xsdbool( strlen( me->characters ) eq 0 ).
  endmethod.

  method stack~peek.
    check not me->stack~empty( ).

    top_element = me->characters(1).
  endmethod.

  method stack~get_size.
    size = strlen( me->characters ).
  endmethod.

  method stack~stringify.
    stringified_stack = cond string(
      when me->stack~empty( )
      then `empty`
      else me->characters ).
  endmethod.

  method constructor.
    check characters is not initial.

    me->characters = characters.
  endmethod.
endclass.

class integer_stack definition.
  public section.
    interfaces:
      stack.

    methods:
      constructor
        importing
          integers type int4_table optional.

  private section.
    data:
      integers type int4_table.
endclass.

class integer_stack implementation.
  method stack~push.
    append new_element to me->integers.

    new_stack = me.
  endmethod.

  method stack~pop.
    if not me->stack~empty( ).
      top_element = me->integers[ me->stack~get_size( ) ].

      delete me->integers index me->stack~get_size( ).
    endif.

    new_stack = me.
  endmethod.

  method stack~empty.
    is_empty = xsdbool( lines( me->integers ) eq 0 ).
  endmethod.

  method stack~peek.
    check not me->stack~empty( ).

    top_element = me->integers[ lines( me->integers ) ].
  endmethod.

  method stack~get_size.
    size = lines( me->integers ).
  endmethod.

  method stack~stringify.
    stringified_stack = cond string(
      when me->stack~empty( )
      then `empty`
      else reduce string(
        init stack = ``
        for integer in me->integers
        next stack = |{ integer }{ stack }| ) ).
  endmethod.

  method constructor.
    check integers is not initial.

    me->integers = integers.
  endmethod.
endclass.

start-of-selection.
  data:
    stack1        type ref to stack,
    stack2        type ref to stack,
    stack3        type ref to stack,

    top_character type char1,
    top_integer   type int4.

  stack1 = new character_stack( ).
  stack2 = new integer_stack( ).
  stack3 = new integer_stack( ).

  write: |Stack1 = { stack1->stringify( ) }|, /.
  stack1->push( 'a' )->push( 'b' )->push( 'c' )->push( 'd' ).
  write: |push a, push b, push c, push d -> Stack1 = { stack1->stringify( ) }|, /.
  stack1->pop( )->pop( importing top_element = top_character ).
  write: |pop, pop and return element -> { top_character }, Stack1 = { stack1->stringify( ) }|, /, /.

  write: |Stack2 = { stack2->stringify( ) }|, /.
  stack2->push( 1 )->push( 2 )->push( 3 )->push( 4 ).
  write: |push 1, push 2, push 3, push 4 -> Stack2 = { stack2->stringify( ) }|, /.
  stack2->pop( )->pop( importing top_element = top_integer ).
  write: |pop, pop and return element -> { top_integer }, Stack2 = { stack2->stringify( ) }|, /, /.

  write: |Stack3 = { stack3->stringify( ) }|, /.
  stack3->pop( ).
  write: |pop -> Stack3 = { stack3->stringify( ) }|, /, /.

Implement a stack with basic operations such as push (to add an element to the top of the stack), pop (to remove and return the last pushed element from the stack), and empty (to check if the stack contains no elements). The stack follows a Last In, First Out (LIFO) access policy. This code is compatible with ABAP Version 7.40 and above.


FORM fibonacci_iter USING index TYPE i
                    CHANGING number_fib TYPE i.
  DATA: lv_old type i,
        lv_cur type i.
  Do index times.
    If sy-index = 1 or sy-index = 2.
      lv_cur = 1.
      lv_old = 0.
    endif.
    number_fib = lv_cur + lv_old.
    lv_old = lv_cur.
    lv_cur = number_fib.
  enddo.
ENDFORM.

Works with: ABAP version 7.4 SP08 Or above only
cl_demo_output=>display( REDUCE #( INIT fibnm = VALUE stringtab( ( |0| ) ( |1| ) )
                                        n TYPE string
                                        x = `0`
                                        y = `1`
                                      FOR i = 1 WHILE i <= 100
                                     NEXT n = ( x + y )
                                          fibnm = VALUE #( BASE fibnm ( n ) )
                                          x = y
                                          y = n ) ).

generate the nth Fibonacci number, using either an iterative or recursive approach. The function also has an optional feature to support negative Fibonacci sequences.


report zday_of_week
data: lv_start type i value 2007,
      lv_n type i value 114,
      lv_date type sy-datum,
      lv_weekday type string,
      lv_day type c,
      lv_year type n length 4.

write 'December 25 is a Sunday in: '.
do lv_n times.
   lv_year = lv_start + sy-index.
   concatenate lv_year '12' '25' into lv_date.
   call function 'DATE_COMPUTE_DAY'
    exporting date = lv_date
    importing day  = lv_day.

   select single langt from t246 into lv_weekday
     where sprsl = sy-langu and
     wotnr = lv_day.

   if lv_weekday eq 'Sunday'.
     write / lv_year.
   endif.
enddo.

The code determines the years between 2008 and 2121 where Christmas (25th December) falls on a Sunday, using standard date handling libraries. It also compares the results with other languages to identify any anomalies in date/time representation, such as overflow issues similar to y2k problems.


report z_quicksort.

data(numbers) = value int4_table( ( 4 ) ( 65 ) ( 2 ) ( -31 ) ( 0 ) ( 99 ) ( 2 ) ( 83 ) ( 782 ) ( 1 ) ).
perform quicksort changing numbers.

write `[`.
loop at numbers assigning field-symbol(<numbers>).
  write <numbers>.
endloop.
write `]`.

form quicksort changing numbers type int4_table.
  data(less) = value int4_table( ).
  data(equal) = value int4_table( ).
  data(greater) = value int4_table( ).

  if lines( numbers ) > 1.
    data(pivot) = numbers[ lines( numbers ) / 2 ].

    loop at numbers assigning field-symbol(<number>).
      if <number> < pivot.
        append <number> to less.
      elseif <number> = pivot.
        append <number> to equal.
      elseif <number> > pivot.
        append <number> to greater.
      endif.
    endloop.

    perform quicksort changing less.
    perform quicksort changing greater.

    clear numbers.
    append lines of less to numbers.
    append lines of equal to numbers.
    append lines of greater to numbers.
  endif.
endform.

implement the quicksort algorithm to sort an array or list of elements. The algorithm works by choosing a pivot element and dividing the rest of the elements into two partitions - one with elements less than the pivot and the other with elements greater than the pivot. It then recursively sorts these partitions and combines them with the pivot to produce a sorted array. The codes also consider different scenarios for optimal and worst-case pivots. The codes can either allocate new arrays or sort in place, and the pivot element can be chosen in various ways. The codes are optimized for ABAP Version 7.40 and above.


report zdate.
data: lv_month type string,
      lv_weekday type string,
      lv_date type string,
      lv_day type c.

call function 'DATE_COMPUTE_DAY'
  exporting date = sy-datum
  importing day  = lv_day.
select single ltx from t247 into lv_month
  where spras = sy-langu and
  mnr = sy-datum+4(2).

select single langt from t246 into lv_weekday
  where sprsl = sy-langu and
  wotnr = lv_day.

concatenate lv_weekday ', ' lv_month ' ' sy-datum+6(2) ', ' sy-datum(4) into lv_date respecting blanks.
write lv_date.
concatenate sy-datum(4) '-' sy-datum+4(2) '-' sy-datum+6(2) into lv_date.
write / lv_date.

display the current date in two formats: "2007-11-23" and "Friday, November 23, 2007".


report z_powerset.

interface set.
  methods:
    add_element
      importing
        element_to_be_added type any
      returning
        value(new_set)      type ref to set,

    remove_element
      importing
        element_to_be_removed type any
      returning
        value(new_set)        type ref to set,

    contains_element
      importing
        element_to_be_found type any
      returning
        value(contains)     type abap_bool,

    get_size
      returning
        value(size) type int4,

    is_equal
      importing
        set_to_be_compared_with type ref to set
      returning
        value(equal)            type abap_bool,

    get_elements
      exporting
        elements type any table,

    stringify
      returning
        value(stringified_set) type string.
endinterface.

class string_set definition.
  public section.
    interfaces:
      set.

    methods:
      constructor
        importing
          elements type stringtab optional,

      build_powerset
        returning
          value(powerset) type ref to string_set.

  private section.
    data elements type stringtab.
endclass.

class string_set implementation.
  method constructor.
    loop at elements into data(element).
      me->set~add_element( element ).
    endloop.
  endmethod.

  method set~add_element.
    if not line_exists( me->elements[ table_line = element_to_be_added ] ).
      append element_to_be_added to me->elements.
    endif.

    new_set = me.
  endmethod.

  method set~remove_element.
    if line_exists( me->elements[ table_line = element_to_be_removed ] ).
      delete me->elements where table_line = element_to_be_removed.
    endif.

    new_set = me.
  endmethod.

  method set~contains_element.
    contains = cond abap_bool(
      when line_exists( me->elements[ table_line = element_to_be_found ] )
      then abap_true
      else abap_false ).
  endmethod.

  method set~get_size.
    size = lines( me->elements ).
  endmethod.

  method set~is_equal.
    if set_to_be_compared_with->get_size( ) ne me->set~get_size( ).
      equal = abap_false.

      return.
    endif.

    loop at me->elements into data(element).
      if not set_to_be_compared_with->contains_element( element ).
        equal = abap_false.

        return.
      endif.
    endloop.

    equal = abap_true.
  endmethod.

  method set~get_elements.
    elements = me->elements.
  endmethod.

  method set~stringify.
    stringified_set = cond string(
      when me->elements is initial
      then `∅`
      when me->elements eq value stringtab( ( `∅` ) )
      then `{ ∅ }`
      else reduce string(
        init result = `{ `
        for element in me->elements
        next result = cond string(
          when element eq ``
          then |{ result }∅, |
          when strlen( element ) eq 1 and element ne `∅`
          then |{ result }{ element }, |
          else |{ result }\{{ element }\}, | ) ) ).

    stringified_set = replace(
      val = stringified_set
      regex = `, $`
      with = ` }`).
  endmethod.

  method build_powerset.
    data(powerset_elements) = value stringtab( ( `` ) ).

    loop at me->elements into data(element).
      do lines( powerset_elements ) times.
        if powerset_elements[ sy-index ] ne `∅`.
          append |{ powerset_elements[ sy-index ] }{ element }| to powerset_elements.
        else.
          append element to powerset_elements.
        endif.
      enddo.
    endloop.

    powerset = new string_set( powerset_elements ).
  endmethod.
endclass.

start-of-selection.
  data(set1) = new string_set( ).
  data(set2) = new string_set( ).
  data(set3) = new string_set( ).

  write: |𝑷( { set1->set~stringify( ) } ) -> { set1->build_powerset( )->set~stringify( ) }|, /.

  set2->set~add_element( `∅` ).
  write: |𝑷( { set2->set~stringify( ) } ) -> { set2->build_powerset( )->set~stringify( ) }|, /.

  set3->set~add_element( `1` )->add_element( `2` )->add_element( `3` )->add_element( `3` )->add_element( `4`
    )->add_element( `4` )->add_element( `4` ).
  write: |𝑷( { set3->set~stringify( ) } ) -> { set3->build_powerset( )->set~stringify( ) }|, /.

The code takes a set S as input and generates its power set. The power set includes all possible subsets of the input set, including the empty set and the set itself. It also handles edge cases where the input set is empty or contains only the empty set. The code is compatible with ABAP Version 7.40 and above.


TYPES: tty_int TYPE STANDARD TABLE OF i
                    WITH NON-UNIQUE DEFAULT KEY.

DATA(itab) = VALUE tty_int( ( 1 )
                            ( 2 )
                            ( 3 ) ).

INSERT 4 INTO TABLE itab.
APPEND 5 TO itab.
DELETE itab INDEX 1.

cl_demo_output=>display( itab ).
cl_demo_output=>display( itab[ 2 ] ).

demonstrate the basic syntax of arrays in a specific language, including the creation of an array, assignment of values, and retrieval of elements. It covers both fixed-length and dynamic arrays, and also showcases the use of a construct called internal tables in the absence of real arrays in ABAP.


REPORT z_test_rosetta_collection.

CLASS lcl_collection DEFINITION CREATE PUBLIC.

  PUBLIC SECTION.
    METHODS: start.
ENDCLASS.

CLASS lcl_collection IMPLEMENTATION.
  METHOD start.
    DATA(itab) = VALUE int4_table( ( 1 ) ( 2 ) ( 3 ) ).

    cl_demo_output=>display( itab ).
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  NEW lcl_collection( )->start( ).

Create and populate a collection in a statically-typed language. Review and ensure the code examples meet the task requirements.


report z_align no standard page header.
start-of-selection.

data: lt_strings type standard table of string,
      lv_strings type string.
append: 'Given$a$text$file$of$many$lines,$where$fields$within$a$line$' to lt_strings,
        'are$delineated$by$a$single$''dollar''$character,$write$a$program' to lt_strings,
        'that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$' to lt_strings,
        'column$are$separated$by$at$least$one$space.' to lt_strings,
        'Further,$allow$for$each$word$in$a$column$to$be$either$left$' to lt_strings,
        'justified,$right$justified,$or$center$justified$within$its$column.' to lt_strings.
types ty_strings type standard table of string.

perform align_col using 'LEFT' lt_strings.
skip.
perform align_col using 'RIGHT' lt_strings.
skip.
perform align_col using 'CENTER' lt_strings.

form align_col using iv_just type string iv_strings type ty_strings.
  constants: c_del value '$'.
  data: lv_string type string,
        lt_strings type table of string,
        lt_tables like table of lt_strings,
        lv_first type string,
        lv_second type string,
        lv_longest type i value 0,
        lv_off type i value 0,
        lv_len type i.
  " Loop through the supplied text. It is expected at the input is a table of strings, with each
  " entry in the table representing a new line of the input.
  loop at iv_strings into lv_string.
    " Split the current line at the delimiter.
    split lv_string at c_del into lv_first lv_second.
    " Loop through the line splitting at every delimiter.
    do.
      append lv_first to lt_strings.
      lv_len = strlen( lv_first ).
      " Check if the length of the new string is greater than the currently stored length.
      if lv_len > lv_longest.
        lv_longest = lv_len.
      endif.
      if lv_second na c_del.
        " Check if the string is longer than the recorded maximum.
        lv_len = strlen( lv_second ).
        if lv_len > lv_longest.
          lv_longest = lv_len.
        endif.
        append lv_second to lt_strings.
        exit.
      endif.
      split lv_second at c_del into lv_first lv_second.
    enddo.

    append lt_strings to lt_tables.
    clear lt_strings.
  endloop.

  " Loop through each line of input.
  loop at lt_tables into lt_strings.
    " Loop through each word in the line (Separated by specified delimiter).
    loop at lt_strings into lv_string.
      lv_off = ( sy-tabix - 1 ) * ( lv_longest + 2 ).
      case iv_just.
        when 'LEFT'.
          write : at (lv_longest) lv_string left-justified.
        when 'RIGHT'.
          write at (lv_longest) lv_string right-justified.
        when 'CENTER'.
          write at (lv_longest) lv_string centered.
      endcase.
    endloop.
    skip.
    sy-linno = sy-linno - 1.
  endloop.
endform.

Given      a          text       file       of         many       lines,     where      fields     within     a          line
are        delineated by         a          single     'dollar'   character, write      a          program
that       aligns     each       column     of         fields     by         ensuring   that       words      in         each
column     are        separated  by         at         least      one        space.
Further,   allow      for        each       word       in         a          column     to         be         either     left
justified, right      justified, or         center     justified  within     its        column.

     Given          a       text       file         of       many     lines,      where     fields     within          a       line
       are delineated         by          a     single   'dollar' character,      write          a    program
      that     aligns       each     column         of     fields         by   ensuring       that      words         in       each
    column        are  separated         by         at      least        one     space.
  Further,      allow        for       each       word         in          a     column         to         be     either       left
justified,      right justified,         or     center  justified     within        its    column.

  Given        a         text       file        of        many      lines,     where      fields     within       a         line
   are     delineated     by         a        single    'dollar'  character,   write        a       program
   that      aligns      each      column       of       fields       by      ensuring     that      words        in        each
  column      are     separated      by         at       least       one       space.
 Further,    allow       for        each       word        in         a        column       to         be       either      left
justified,   right    justified,     or       center   justified    within      its      column.

The code reads a text file with lines separated by a dollar character. It aligns each column of fields by ensuring at least one space between words in each column. It also allows each word in a column to be left, right, or center justified. The minimum space between columns is computed from the text, not hard-coded. Trailing dollar characters or consecutive spaces at the end of lines do not affect the alignment. The output is suitable for viewing in a mono-spaced font on a plain text editor or basic terminal.


data: lv_flag type c,
      lv_number type i,
      lt_numbers type table of i.

constants: c_no_val type i value 9999.

append 1 to lt_numbers.
append 1 to lt_numbers.
append 2 to lt_numbers.
append 7 to lt_numbers.

write 'Evaluating 24 with the following input: '.
loop at lt_numbers into lv_number.
  write lv_number.
endloop.
perform solve_24 using lt_numbers.

form eval_formula using iv_eval type string changing ev_out type i.
  call function 'EVAL_FORMULA' "analysis of a syntactically correct formula
    exporting
      formula = iv_eval
    importing
      value   = ev_out
    exceptions
   others     = 1.

  if sy-subrc <> 0.
    ev_out = -1.
  endif.
endform.

" Solve a 24 puzzle.
form solve_24 using it_numbers like lt_numbers.
  data: lv_flag   type c,
        lv_op1    type c,
        lv_op2    type c,
        lv_op3    type c,
        lv_var1   type c,
        lv_var2   type c,
        lv_var3   type c,
        lv_var4   type c,
        lv_eval   type string,
        lv_result type i,
        lv_var     type i.

  define retrieve_var.
    read table it_numbers index &1 into lv_var.
    &2 = lv_var.
  end-of-definition.

  define retrieve_val.
    perform eval_formula using lv_eval changing lv_result.
    if lv_result = 24.
        write / lv_eval.
    endif.
  end-of-definition.
  " Loop through all the possible number permutations.
  do.
    " Init. the operations table.

    retrieve_var: 1 lv_var1, 2 lv_var2, 3 lv_var3, 4 lv_var4.
    do 4 times.
      case sy-index.
        when 1.
          lv_op1 = '+'.
        when 2.
          lv_op1 = '*'.
        when 3.
          lv_op1 = '-'.
        when 4.
          lv_op1 = '/'.
      endcase.
      do 4 times.
        case sy-index.
        when 1.
          lv_op2 = '+'.
        when 2.
          lv_op2 = '*'.
        when 3.
          lv_op2 = '-'.
        when 4.
          lv_op2 = '/'.
        endcase.
        do 4 times.
          case sy-index.
          when 1.
            lv_op3 = '+'.
          when 2.
            lv_op3 = '*'.
          when 3.
            lv_op3 = '-'.
          when 4.
            lv_op3 = '/'.
          endcase.
          concatenate '(' '(' lv_var1 lv_op1 lv_var2 ')' lv_op2 lv_var3 ')' lv_op3 lv_var4  into lv_eval separated by space.
          retrieve_val.
          concatenate '(' lv_var1 lv_op1 lv_var2 ')' lv_op2 '(' lv_var3 lv_op3 lv_var4 ')'  into lv_eval separated by space.
          retrieve_val.
          concatenate '(' lv_var1 lv_op1 '(' lv_var2 lv_op2 lv_var3 ')' ')' lv_op3 lv_var4  into lv_eval separated by space.
          retrieve_val.
          concatenate lv_var1 lv_op1 '(' '(' lv_var2 lv_op2 lv_var3 ')' lv_op3 lv_var4 ')'  into lv_eval separated by space.
          retrieve_val.
          concatenate lv_var1 lv_op1 '(' lv_var2 lv_op2 '(' lv_var3 lv_op3 lv_var4 ')' ')'  into lv_eval separated by space.
          retrieve_val.
        enddo.
      enddo.
    enddo.

    " Once we've reached the last permutation -> Exit.
    perform permute using it_numbers changing lv_flag.
    if lv_flag = 'X'.
      exit.
    endif.
  enddo.
endform.

" Permutation function - this is used to permute:
" A = {A1...AN} -> Set of supplied variables.
" B = {B1...BN - 1} -> Set of operators.
" Can be used for an unbounded size set. Relies
" on lexicographic ordering of the set.
form permute using iv_set like lt_numbers
             changing ev_last type c.
  data: lv_len     type i,
        lv_first   type i,
        lv_third   type i,
        lv_count   type i,
        lv_temp    type i,
        lv_temp_2  type i,
        lv_second  type i,
        lv_changed type c,
        lv_perm    type i.
  describe table iv_set lines lv_len.

  lv_perm = lv_len - 1.
  lv_changed = ' '.
  " Loop backwards through the table, attempting to find elements which
  " can be permuted. If we find one, break out of the table and set the
  " flag indicating a switch.
  do.
    if lv_perm <= 0.
      exit.
    endif.
    " Read the elements.
    read table iv_set index lv_perm into lv_first.
    add 1 to lv_perm.
    read table iv_set index lv_perm into lv_second.
    subtract 1 from lv_perm.
    if lv_first < lv_second.
      lv_changed = 'X'.
      exit.
    endif.
    subtract 1 from lv_perm.
  enddo.

  " Last permutation.
  if lv_changed <> 'X'.
    ev_last = 'X'.
    exit.
  endif.

  " Swap tail decresing to get a tail increasing.
  lv_count = lv_perm + 1.
  do.
    lv_first = lv_len + lv_perm - lv_count + 1.
    if lv_count >= lv_first.
      exit.
    endif.

    read table iv_set index lv_count into lv_temp.
    read table iv_set index lv_first into lv_temp_2.
    modify iv_set index lv_count from lv_temp_2.
    modify iv_set index lv_first from lv_temp.
    add 1 to lv_count.
  enddo.

  lv_count = lv_len - 1.
  do.
    if lv_count <= lv_perm.
      exit.
    endif.

    read table iv_set index lv_count into lv_first.
    read table iv_set index lv_perm into lv_second.
    read table iv_set index lv_len into lv_third.
    if ( lv_first < lv_third ) and ( lv_first > lv_second ).
      lv_len = lv_count.
    endif.

    subtract 1 from lv_count.
  enddo.

  read table iv_set index lv_perm into lv_temp.
  read table iv_set index lv_len into lv_temp_2.
  modify iv_set index lv_perm from lv_temp_2.
  modify iv_set index lv_len from lv_temp.
endform.

The code takes four digits as input, either from the user or randomly generated, and computes all possible arithmetic expressions following the rules of the 24 game. It also displays examples of the solutions it generates.


form factorial using iv_val type i.
  data: lv_res type i value 1.
  do iv_val times.
    multiply lv_res by sy-index.
  enddo.

  iv_val = lv_res.
endform.

form fac_rec using iv_val type i.
  data: lv_temp type i.

  if iv_val = 0.
    iv_val = 1.
  else.
    lv_temp = iv_val - 1.
    perform fac_rec using lv_temp.
    multiply iv_val by lv_temp.
  endif.
endform.

The code defines a function that calculates the factorial of a given number. The factorial is the product of all positive integers from the given number down to 1. The function can be implemented either iteratively or recursively. It optionally includes error handling for negative input numbers. It is related to the task of generating primorial numbers.


report zdot_product
data: lv_n type i,
      lv_sum type i,
      lt_a type standard table of i,
      lt_b type standard table of i.

append: '1' to lt_a, '3' to lt_a, '-5' to lt_a.
append: '4' to lt_b, '-2' to lt_b, '-1' to lt_b.
describe table lt_a lines lv_n.

perform dot_product using lt_a lt_b lv_n changing lv_sum.

write lv_sum left-justified.

form dot_product using it_a like lt_a
                       it_b like lt_b
                       iv_n type i
                 changing
                       ev_sum type i.
  field-symbols: <wa_a> type i, <wa_b> type i.

  do iv_n times.
    read table: it_a assigning <wa_a> index sy-index, it_b assigning <wa_b> index sy-index.
    lv_sum = lv_sum + ( <wa_a> * <wa_b> ).
  enddo.
endform.

Implement a function to calculate the dot product of two vectors of arbitrary length. The function multiplies corresponding elements from each vector and sums the products. The vectors must be of the same length. Example vectors used are [1, 3, -5] and [4, -2, -1].


DATA: xml_string TYPE string.

DATA(xml)  = cl_ixml=>create( ).
DATA(doc)  = xml->create_document( ).
DATA(root) = doc->create_simple_element( name   = 'root'
                                         parent = doc ).

doc->create_simple_element( name   = 'element'
                            parent = root
                            value  = 'Some text here' ).

DATA(stream_factory) = xml->create_stream_factory( ).
DATA(stream)         = stream_factory->create_ostream_cstring( string = xml_string ).
DATA(renderer)       = xml->create_renderer( document = doc
                                             ostream  = stream ).
stream->set_pretty_print( abap_true ).
renderer->render( ).

cl_demo_output=>display_text( xml_string ).

<?xml version="1.0" encoding="utf-16"?>
<root>
<element>Some text here</element>
</root>

Create a simple DOM and serialize it into XML format. The XML output includes a root element containing a single element with some text.


the system time in a specified unit. This can be used for debugging, network information, random number seeds, or program performance. The time is retrieved either by a system command or a built-in language function. It is related to the task of date formatting and retrieving system time.


REPORT guess_the_number.

DATA prng TYPE REF TO cl_abap_random_int.

cl_abap_random_int=>create(
  EXPORTING
    seed = cl_abap_random=>seed( )
    min  = 1
    max  = 10
  RECEIVING
    prng = prng ).

DATA(number) = prng->get_next( ).

DATA(field) = VALUE i( ).

cl_demo_input=>add_field( EXPORTING text = |Choice one number between 1 and 10| CHANGING field = field ).
cl_demo_input=>request( ).

WHILE number <> field.
  cl_demo_input=>add_field( EXPORTING text = |You miss, try again| CHANGING field = field ).
  cl_demo_input=>request( ).
ENDWHILE.

cl_demo_output=>display( |Well Done| ).

"Implement a number guessing game where the computer selects a number between 1 and 10. The player is repeatedly prompted to guess the number until the correct number is guessed, upon which a 'Well guessed!' message is displayed and the program terminates. A conditional loop is used to facilitate repeated guessing."


REPORT lower_case_ascii.

WRITE: / to_lower( sy-abcde ).

REPORT lower_case_ascii.

cl_demo_output=>new(
          )->begin_section( |Generate lower case ASCII alphabet|
          )->write( REDUCE string( INIT out TYPE string
                                    FOR char = 1 UNTIL char > strlen( sy-abcde )
                                   NEXT out = COND #( WHEN out IS INITIAL THEN sy-abcde(1)
                                                      ELSE |{ out } { COND string( WHEN char <> strlen( sy-abcde ) THEN sy-abcde+char(1) ) }| ) )
          )->write( |Or use the system field: { sy-abcde }|
          )->display( ).

generate a sequence of all lower case ASCII characters from a to z. This is done in a reliable coding style suitable for large programs, using strong typing if available. The code avoids manual enumeration of characters to prevent bugs. It also demonstrates how to access a similar sequence from the standard library if it exists.


  DATA: X1 TYPE F, Y1 TYPE F,
        X2 TYPE F, Y2 TYPE F, YD TYPE F,
        PI TYPE F,
        PI_180 TYPE F,
        MINUS_1 TYPE F VALUE '-1'.

PI     = ACOS( MINUS_1 ).
PI_180 = PI / 180.

LATITUDE1 = 36,12 . LONGITUDE1 = -86,67 .
LATITUDE2 = 33,94 . LONGITUDE2 = -118,4 .

  X1 = LATITUDE1  * PI_180.
  Y1 = LONGITUDE1 * PI_180.
  X2 = LATITUDE2  * PI_180.
  Y2 = LONGITUDE2 * PI_180.
  YD = Y2 - Y1.

  DISTANCE = 20000 / PI *
    ACOS( SIN( X1 ) * SIN( X2 ) + COS( X1 ) * COS( X2 ) * COS( YD ) ).

WRITE : 'Distance between given points = ' , distance , 'km .' .

Implement a function to calculate the great-circle distance between two points on a sphere using the Haversine formula. The function takes the coordinates of Nashville International Airport (BNA) and Los Angeles International Airport (LAX) as input and returns the distance between them. The calculation uses the recommended earth radius of 6372.8 km or 6371 km, depending on the level of precision required.


report z_http.

cl_http_client=>create_by_url(
  exporting
    url                = `http://rosettacode.org/robots.txt`
  importing
    client             = data(http_client)
  exceptions
    argument_not_found = 1
    plugin_not_active  = 2
    internal_error     = 3
    others             = 4 ).

if sy-subrc <> 0.
  data(error_message) = switch string( sy-subrc
    when 1 then `argument_not_found`
    when 2 then `plugin_not_active`
    when 3 then `internal_error`
    when 4 then `other error` ).

  write error_message.
  exit.
endif.

data(rest_http_client) = cast if_rest_client( new cl_rest_http_client( http_client ) ).

rest_http_client->get( ).

data(response_string) = rest_http_client->get_response_entity( )->get_string_data( ).

split response_string at cl_abap_char_utilities=>newline into table data(output_table).

loop at output_table assigning field-symbol(<output_line>).
  write / <output_line>.
endloop.

Accesses and prints the content of a specified URL to the console using HTTP protocol, compatible with ABAP Version 7.40 and above.


METHOD luhn_check.

  DATA: sum(1) TYPE n VALUE 0. " Sum of checksum.
  DATA: current TYPE i. " Current digit.
  DATA: odd TYPE i VALUE 1. " Multiplier.
  DATA: len TYPE i. " String crowler.

  " Luhn algorithm.
  len = NUMOFCHAR( pi_string ) - 1.
  WHILE ( len >= 0 ).
    current = pi_string+len(1) * odd.
    IF ( current > 9 ).
      current = current - 9. " Digits sum.
    ENDIF.
    sum = sum + current.
    odd = 3 - odd. " 1 <--> 2 Swich
    len = len - 1. " Move to next charcter.
  ENDWHILE.

  " Validation check.
  IF ( sum = 0 ).
    pr_valid = abap_true.
  ELSE.
    pr_valid = abap_false.
  ENDIF.

ENDMETHOD.

The code validates credit card numbers using the Luhn test. It reverses the input number, calculates the sum of odd and even positioned digits (with even digits being doubled and if the result is greater than nine, the digits of the result are summed). If the total sum ends in zero, the number is deemed valid. The code tests this functionality on four given numbers.


report z_repeat_string.

write repeat( val = `ha`  occ = 5 ).

The code takes a string and a number as input, repeats the string the given number of times and returns the resulting string. It also includes a more efficient method to repeat a single character. This is applicable for ABAP Version 7.40 and above.


DATA: text TYPE string VALUE 'This is a Test'.

FIND FIRST OCCURRENCE OF REGEX 'is' IN text.
IF sy-subrc = 0.
  cl_demo_output=>write( 'Regex matched' ).
ENDIF.

REPLACE ALL OCCURRENCES OF REGEX '[t|T]est' IN text WITH 'Regex'.

cl_demo_output=>write( text ).
cl_demo_output=>display( ).

Regex matched

This is a Regex

"Matches a string with a regular expression and performs substitution on a part of the string using the same regular expression."


report zz_arithmetic no standard page heading.

" Read in the two numbers from the user.
selection-screen begin of block input.
  parameters: p_first type i,
              p_second type i.
selection-screen end of block input.

" Set the text value that is displayed on input request.
at selection-screen output.
  %_p_first_%_app_%-text  = 'First Number: '.
  %_p_second_%_app_%-text = 'Second Number: '.

end-of-selection.
  data: lv_result type i.
  lv_result = p_first + p_second.
  write: / 'Addition:', lv_result.
  lv_result = p_first - p_second.
  write: / 'Substraction:', lv_result.
  lv_result = p_first * p_second.
  write: / 'Multiplication:', lv_result.
  lv_result = p_first div p_second.
  write: / 'Integer quotient:', lv_result. " Truncated towards zero.
  lv_result = p_first mod p_second.
  write: / 'Remainder:',  lv_result.

take two integers as input from the user and display their sum, difference, product, integer quotient, remainder, and exponentiation. The code also indicates the rounding direction for the quotient and the sign of the remainder. It does not include error handling. A bonus feature is the inclusion of the `divmod` operator example.


CLASS lcl_binom DEFINITION CREATE PUBLIC.

  PUBLIC SECTION.
    CLASS-METHODS:
      calc
        IMPORTING n               TYPE i
                  k               TYPE i
        RETURNING VALUE(r_result) TYPE f.

ENDCLASS.

CLASS lcl_binom IMPLEMENTATION.

  METHOD calc.

    r_result = 1.
    DATA(i) = 1.
    DATA(m) = n.

    WHILE i <= k.
      r_result = r_result * m / i.
      i = i + 1.
      m = m - 1.
    ENDWHILE.

  ENDMETHOD.

ENDCLASS.

The code calculates any binomial coefficient using the provided formula. It is specifically designed to output the binomial coefficient of 5 choose 3, which is 10. It also includes tasks for generating combinations and permutations, both with and without replacement.


report zz_incstring
perform test using: '0', '1', '-1', '10000000', '-10000000'.

form test using iv_string type string.
  data: lv_int  type i,
        lv_string type string.
  lv_int = iv_string + 1.
  lv_string = lv_int.
  concatenate '"' iv_string '" + 1 = "' lv_string '"' into lv_string.
  write / lv_string.
endform.


Works with: ABAP version 7.4 SP05 or Above only
DATA: tab TYPE TABLE OF string.

tab = VALUE #(
  FOR i = 1 WHILE i <= 100 (
    COND string( LET r3 = i MOD 3
                     r5 = i MOD 5 IN
                 WHEN r3 = 0 AND r5 = 0 THEN |FIZZBUZZ|
                 WHEN r3 = 0            THEN |FIZZ|
                 WHEN r5 = 0            THEN |BUZZ|
                 ELSE i ) ) ).

cl_demo_output=>write( tab ).
cl_demo_output=>display( ).

Works with: ABAP version 7.4 SP05 or Above only
cl_demo_output=>display( value stringtab( for i = 1 until i > 100
                                          let fizz = cond #( when i mod 3 = 0 then |fizz| else space )
                                              buzz = cond #( when i mod 5 = 0 then |buzz| else space )
                                              fb   = |{ fizz }{ buzz }| in
                                         ( switch #( fb when space then i else fb ) ) ) ).

print numbers from 1 to 100, replacing multiples of three with 'Fizz', multiples of five with 'Buzz', and multiples of both three and five with 'FizzBuzz'.


data: lv_string1 type string value 'Test',
      lv_string2 type string.
lv_string2 = lv_string1.

Works with: ABAP version 7.4 Or above only
DATA(string1) = |Test|.
DATA(string2) = string1.

"Implements functionality to copy a string's content and create an additional reference to an existing string where applicable."


report z_mutual_recursion.

class hoffstadter_sequences definition.
  public section.
    class-methods:
      f
        importing
          n             type int4
        returning
          value(result) type int4,

      m
        importing
          n             type int4
        returning
          value(result) type int4.
endclass.

class hoffstadter_sequences implementation.
  method f.
    result = cond int4(
      when n eq 0
      then 1
      else n - m( f( n - 1 ) ) ).
  endmethod.

  method m.
    result = cond int4(
      when n eq 0
      then 0
      else n - f( m( n - 1 ) ) ).
  endmethod.
endclass.

start-of-selection.
  write: |{ reduce string(
    init results = |f(0 - 19): { hoffstadter_sequences=>f( 0 ) }|
    for i = 1 while i < 20
    next results = |{ results }, { hoffstadter_sequences=>f( i ) }| ) }|, /.

  write: |{ reduce string(
    init results = |m(0 - 19): { hoffstadter_sequences=>m( 0 ) }|
    for i = 1 while i < 20
    next results = |{ results }, { hoffstadter_sequences=>m( i ) }| ) }|, /.

implement two mutually recursive functions to compute the Hofstadter Female and Male sequences. The functions are defined such that each function calls the other during its computation. The solution is applicable for ABAP Version 7.40 and can be implemented in procedural ABAP, with enhanced readability when used with classes.


REPORT Z_DECODE_URL.

DATA: lv_encoded_url TYPE string VALUE 'http%3A%2F%2Ffoo%20bar%2F',
      lv_decoded_url TYPE string.

CALL METHOD CL_HTTP_UTILITY=>UNESCAPE_URL
  EXPORTING
    ESCAPED   = lv_encoded_url
  RECEIVING
    UNESCAPED = lv_decoded_url.

WRITE: 'Encoded URL: ', lv_encoded_url, /, 'Decoded URL: ', lv_decoded_url.

provide a function to convert URL-encoded strings back into their original unencoded form. It includes test cases for strings like "http%3A%2F%2Ffoo%20bar%2F", "google.com/search?q=%60Abdu%27l-Bah%C3%A1", and "%25%32%35".


report z24_with_rpn
constants: c_eval_to   type i value 24,
           c_tolerance type f value '0.0001'.
data: gt_val type table of f,
      gv_val type f,
      gv_pac type p,
      gv_chk type c.
" Log a message from the RPN Calculator.
form rpn_log using lv_msg type string.
  write : / 'RPN Message: ', lv_msg.
endform.

" Performs add in Reverse Polish Notation.
form rpn_add.
  data: lv_val1 type f,
        lv_val2 type f.
  " Get the last two values from the stack to add together.
  perform rpn_pop changing: lv_val1, lv_val2.
  add lv_val2 to lv_val1.
  " Add them and then add them back to the "top".
  perform rpn_push using lv_val1.
endform.

" Perform subtraction in RPN.
form rpn_sub.
  data: lv_val1 type f,
        lv_val2 type f.
  " Get the last two values, subtract them, and push them back on.
  perform rpn_pop changing: lv_val1, lv_val2.
  subtract lv_val1 from lv_val2.
  perform rpn_push using lv_val2.
endform.

" Perform multiplication in RPN.
form rpn_mul.
  data: lv_val1 type f,
        lv_val2 type f.
  " Get the last two values, multiply, and push them back.
  perform rpn_pop changing: lv_val1, lv_val2.
  multiply lv_val1 by lv_val2.
  perform rpn_push using lv_val1.
endform.

" Perform division in RPN.
form rpn_div.
  data: lv_val1 type f,
        lv_val2 type f.
  " Get the last two values, divide the first by the second
  " and then add it back to the stack.
  perform rpn_pop changing: lv_val1, lv_val2.
  divide lv_val1 by lv_val2.
  perform rpn_push using lv_val1.
endform.

" Negate a number in RPN.
form rpn_neg.
  data: lv_val type f.
  " Simply get the last number and negate it before pushing it back.
  perform rpn_pop changing lv_val.
  multiply lv_val by -1.
  perform rpn_push using lv_val.
endform.

" Swap the top two values on the RPN Stack.
form rpn_swap.
  data: lv_val1 type f,
        lv_val2 type f.
  " Get the top two values and then add them back in reverse order.
  perform rpn_pop changing: lv_val1, lv_val2.
  perform rpn_push using: lv_val2, lv_val1.
endform.

" Call the relevant RPN operation.
form rpn_call_op using iv_op type string.
  case iv_op.
    when '+'.
      perform rpn_add.
    when '-'.
      perform rpn_sub.
    when '*'.
      perform rpn_mul.
    when '/'.
      perform rpn_div.
    when 'n'.
      perform rpn_neg.
    when 's'.
      perform rpn_swap.
    when others. " Bad op-code found!
      perform rpn_log using 'Operation not found!'.
    endcase.
endform.

" Reverse_Polish_Notation Parser.
form rpn_pop changing ev_out type f.
  " Attempt to get the entry from the 'top' of the table.
  " If it's empty --> log an error and bail.
  data: lv_lines type i.

  describe table gt_val lines lv_lines.
  if lv_lines > 0.
    " After we have retrieved the value, we must remove it from the table.
    read table gt_val index lv_lines into ev_out.
    delete gt_val index lv_lines.
  else.
    perform rpn_log using 'RPN Stack is empty! Underflow!'.
    ev_out = 0.
  endif.
endform.

" Pushes the supplied value onto the RPN table / stack.
form rpn_push using iv_val type f.
  " Simple append - other languages this involves a stack of a certain size.
  append iv_val to gt_val.
endform.

" Refreshes the RPN stack / table.
form rpn_reset.
  " Clear the stack to start anew.
  refresh gt_val.
endform.

" Checks if the supplied string is numeric.
" Lazy evaluation - only checkcs for numbers without formatting.
form rpn_numeric using    iv_in  type string
                 changing ev_out type c.
  data: lv_moff type i,
        lv_len  type i.
  " Match digits with optional decimal places.
  find regex '\d+(\.\d+)*' in iv_in
    match offset lv_moff
    match length lv_len.
  " Get the offset and length of the first occurence, and work
  " out the length of the match.
  subtract lv_moff from lv_len.
  " If the length is different to the length of the whole string,
  " then it's NOT a match, else it is.
  if lv_len ne strlen( iv_in ).
    ev_out = ' '.
  else.
    ev_out = 'X'.
  endif.
endform.

" Convert input to a number. Added safety net of is_numeric.
form rpn_get_num using iv_in type string changing ev_num type f.
  data: lv_check type c.
  " Check if it's numeric - built in redundancy.
  perform rpn_numeric using iv_in changing lv_check.
  if lv_check = 'X'.
    ev_num = iv_in.
  else.
    perform rpn_log using 'Wrong call!'.
  endif.
endform.

" Evaluate the RPN expression and return true if success in eval.
form rpn_eval using in_expr type string changing ev_out type c.
  data: lv_len  type i,
        lv_off  type i value 0,
        lv_num  type c,
        lv_val  type f,
        lv_tok  type string.

  lv_len = strlen( in_expr ).
  do lv_len times.
    lv_tok = in_expr+lv_off(1).
    perform rpn_numeric using lv_tok changing lv_num.
    if lv_num = 'X'.
      perform: rpn_get_num using lv_tok changing lv_val,
               rpn_push    using lv_val.
    else.

      perform rpn_call_op using lv_tok.
    endif.
    add 1 to lv_off.
  enddo.

  ev_out = 'X'.
endform.
selection-screen begin of block main with frame title lv_title.
  parameters:
    p_first  type i,
    p_second type i,
    p_third  type i,
    p_fourth type i,
    p_expr   type string.
selection-screen end of block main.

initialization.
  perform ranged_rand using 1 9 changing p_first.
  perform ranged_rand using 1 9 changing p_second.
  perform ranged_rand using 1 9 changing p_third.
  perform ranged_rand using 1 9 changing p_fourth.

at selection-screen output.
  " Set-up paramter texts.
  lv_title = 'Reverse Polish Notation Tester - Enter expression that evaluates to 24.'.
  %_p_first_%_app_%-text  = 'First Number: '.
  %_p_second_%_app_%-text = 'Second Number: '.
  %_p_third_%_app_%-text  = 'Third Number: '.
  %_p_fourth_%_app_%-text = 'Fourth Number: '.
  %_p_expr_%_app_%-text   = 'Expression: '.
  " Disallow modification of supplied numbers.
  loop at screen.
    if screen-name = 'P_FIRST' or  screen-name = 'P_SECOND' or
       screen-name = 'P_THIRD' or  screen-name = 'P_FOURTH'.
      screen-input = '0'.
      modify screen.
    endif.
  endloop.

start-of-selection.
  " Check the expression is valid.
  perform check_expr using p_expr changing gv_chk.
  if gv_chk <> 'X'.
    write : / 'Invalid input!'.
    stop.
  endif.
  " Check if the expression actually evalutes.
  perform rpn_eval using p_expr changing gv_chk.
  " If it doesn't, warning!.
  if gv_chk <> 'X'.
    write : / 'Invalid expression!'.
    stop.
  endif.
  " Get the evaluated value. Transform it to something that displays a bit better.
  " Then check if it's a valid answer, with a certain tolerance.
  " If they're wrong, give them instructions to on how to go back.
  perform rpn_pop changing gv_val.
  gv_pac = gv_val.
  gv_val = abs( gv_val - c_eval_to ).
  if gv_val < c_tolerance.
    write : / 'Answer correct'.
  else.
    write : / 'Your expression evalutes to ', gv_pac.
    write : / 'Press "F3" to go back and try again!'.
  endif.
  write : / 'Re-run the program to generate a new set.'.

 " Check that the input expression is valid - i.e. all supplied numbers
 " appears exactly once. This does not validate the expression itself.
form check_expr using iv_exp type string changing ev_ok type c.
  data: lv_chk  type c,
        lv_tok  type string,
        lv_val  type i value 0,
        lv_len  type i,
        lv_off  type i,
        lv_num  type i,
        lt_nums type standard table of i.
  ev_ok = 'X'.
  " Update the number count table - indexes 1-9 correspond to numbers.
  " The value stored corresponds to the number of occurences.
  do 9 times.
    if p_first = sy-index.
      add 1 to lv_val.
    endif.
    if p_second = sy-index.
      add 1 to lv_val.
    endif.
    if p_third = sy-index.
      add 1 to lv_val.
    endif.
    if p_fourth = sy-index.
      add 1 to lv_val.
    endif.

    append lv_val to lt_nums.
    lv_val = 0.
  enddo.
  " Loop through the expression parsing the numbers.
  lv_len = strlen( p_expr ).
  do lv_len times.
    lv_tok = p_expr+lv_off(1). " Check if the current token is a number.
    perform rpn_numeric using lv_tok changing lv_chk.
    if lv_chk = 'X'.
      lv_num = lv_tok. " If it's a number, it must be from 1 - 9.
      if lv_num < 1 or lv_num > 9.
        ev_ok = ' '.
        write : / 'Numbers must be between 1 and 9!'.
        return.
      else.
        " Check how many times the number was supplied. If it wasn't supplied
        " or if we have used it up, we should give an error.
        read table lt_nums index lv_num into lv_val.
        if lv_val <= 0.
          ev_ok = ' '.
          write : / 'You can not use numbers more than once'.
          return.
        endif.
        " If we have values left for this number, we decrement the remaining amount.
        subtract 1 from lv_val.
        modify lt_nums index lv_num from lv_val.
      endif.
    endif.
    add 1 to lv_off.
  enddo.
  " Loop through the table and check we have no numbers left for use.
  do 9 times.
    read table lt_nums index  sy-index into lv_val.
    if lv_val > 0.
      write : / 'You must use all numbers'.
      ev_ok = ' '.
      return.
     endif.
  enddo.
endform.

" Generate a random number within the given range.
form ranged_rand using iv_min type i iv_max type i
                 changing ev_val type i.
  call function 'QF05_RANDOM_INTEGER'
    exporting
      ran_int_max = iv_max
      ran_int_min = iv_min
    importing
      ran_int     = ev_val.
endform.

The code randomly selects and displays four digits from 1 to 9. It then prompts the player to input an arithmetic expression using these digits exactly once each. The code checks and evaluates the expression to see if it equals 24. The allowed operations are multiplication, division, addition, and subtraction, with division preserving remainders. The code does not allow the formation of multi-digit numbers from the given digits. The order of the digits does not have to be preserved. The type of expression evaluator used is not specified. The code does not generate the expression or test if an expression is possible.


DATA: s1 TYPE string,
      s2 TYPE string.

s1 = 'Hello'.
CONCATENATE s1 ' literal' INTO s2 RESPECTING BLANKS.
WRITE: / s1.
WRITE: / s2.

Initializes two string variables, one with a text value and the other as a concatenation of the first variable and a string literal, then displays their content.


report zz_anagrams no standard page heading.
define update_progress.
  call function 'SAPGUI_PROGRESS_INDICATOR'
    exporting
      text = &1.
end-of-definition.

" Selection screen segment allowing the person to choose which file will act as input.
selection-screen begin of block file_choice.
  parameters p_file type string lower case.
selection-screen end of block file_choice.

" When the user requests help with input, run the routine to allow them to navigate the presentation server.
at selection-screen on value-request for p_file.
  perform getfile using p_file.

at selection-screen output.
  %_p_file_%_app_%-text = 'Input File: '.

start-of-selection.
  data: gt_data type table of string.

  " Read the specified file from the presentation server into memory.
  perform readfile using p_file changing gt_data.
  " After the file has been read into memory, loop through it line-by-line and make anagrams.
  perform anagrams using gt_data.

" Subroutine for generating a list of anagrams.
" The supplied input is a table, with each entry corresponding to a word.
form anagrams using it_data like gt_data.
  types begin of ty_map.
    types key type string.
    types value type string.
  types end of ty_map.

  data: lv_char     type c,
        lv_len      type i,
        lv_string   type string,
        ls_entry    type ty_map,
        lt_anagrams type standard table of ty_map,
        lt_c_tab    type table of string.

  field-symbols: <fs_raw> type string.
  " Loop through each word in the table, and make an associative array.
  loop at gt_data assigning <fs_raw>.
    " First, we need to re-order the word alphabetically. This generated a key. All anagrams will use this same key.
    " Add each character to a table, which we will then sort alphabetically.
    lv_len = strlen( <fs_raw> ).
    refresh lt_c_tab.
    do lv_len times.
      lv_len = sy-index  - 1.
      append <fs_raw>+lv_len(1) to lt_c_tab.
    enddo.
    sort lt_c_tab as text.
    " Now append the characters to a string and add it as a key into the map.
    clear lv_string.
    loop at lt_c_tab into lv_char.
      concatenate lv_char lv_string into lv_string respecting blanks.
    endloop.
    ls_entry-key = lv_string.
    ls_entry-value = <fs_raw>.
    append ls_entry to lt_anagrams.
  endloop.
  " After we're done processing, output a list of the anagrams.
  clear lv_string.
  loop at lt_anagrams into ls_entry.
    " Is it part of the same key --> Output in the same line, else a new entry.
    if lv_string = ls_entry-key.
        write: ', ', ls_entry-value.
    else.
      if sy-tabix <> 1.
        write: ']'.
      endif.
      write:  / '[', ls_entry-value.
    endif.
    lv_string = ls_entry-key.
  endloop.
  " Close last entry.
  write ']'.
endform.

" Read a specified file from the presentation server.
form readfile using i_file type string changing it_raw like gt_data.
  data: l_datat type string,
        l_msg(2048),
        l_lines(10).

  " Read the file into memory.
  update_progress 'Reading file...'.
  call method cl_gui_frontend_services=>gui_upload
    exporting
      filename = i_file
    changing
      data_tab = it_raw
    exceptions
      others   = 1.
  " Output error if the file could not be uploaded.
  if sy-subrc <> 0.
    write : / 'Error reading the supplied file!'.
    return.
  endif.
endform.

"Code identifies sets of anagrams with the most words from the provided word list."


REPORT  zhuberv_ackermann.

CLASS zcl_ackermann DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS ackermann IMPORTING m TYPE i
                                      n TYPE i
                            RETURNING value(v) TYPE i.
ENDCLASS.            "zcl_ackermann DEFINITION

CLASS zcl_ackermann IMPLEMENTATION.

  METHOD: ackermann.

    DATA: lv_new_m TYPE i,
          lv_new_n TYPE i.

    IF m = 0.
      v = n + 1.
    ELSEIF m > 0 AND n = 0.
      lv_new_m = m - 1.
      lv_new_n = 1.
      v = ackermann( m = lv_new_m n = lv_new_n ).
    ELSEIF m > 0 AND n > 0.
      lv_new_m = m - 1.

      lv_new_n = n - 1.
      lv_new_n = ackermann( m = m n = lv_new_n ).

      v = ackermann( m = lv_new_m n = lv_new_n ).
    ENDIF.

  ENDMETHOD.                    "ackermann

ENDCLASS.                    "zcl_ackermann IMPLEMENTATION

PARAMETERS: pa_m TYPE i,
            pa_n TYPE i.

DATA: lv_result TYPE i.

START-OF-SELECTION.
  lv_result = zcl_ackermann=>ackermann( m = pa_m n = pa_n ).
  WRITE: / lv_result.

Implement the Ackermann function which is a recursive function that takes two non-negative arguments and returns a value based on the specified conditions. The function should ideally support arbitrary precision due to its rapid growth.


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.
  BREAK-POINT.
*&---------------------------------------------------------------------*
*&      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.

  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.

  PERFORM get_position USING p_i p_j 'R' CHANGING p_result p_matrix.
  CHECK p_result NE 'X'.

  PERFORM check_horizontal USING p_i p_j CHANGING p_result p_matrix.
  CHECK p_result NE 'X'.

  PERFORM check_vertical USING p_i p_j CHANGING p_result p_matrix.
  CHECK p_result NE 'X'.

  PERFORM check_diagonals USING p_i p_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.

  ADD 1 TO gv_solut.

  WRITE:/ 'Solution: ', gv_solut.

  DO p_number TIMES.
    CONCATENATE lv_colum '----' INTO lv_colum.
  ENDDO.

  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

"Solve the N-queens problem for an NxN board and provide the number of solutions for small values of N."


report z_array_concatenation.

data(itab1) = value int4_table( ( 1 ) ( 2 ) ( 3 ) ).
data(itab2) = value int4_table( ( 4 ) ( 5 ) ( 6 ) ).

append lines of itab2 to itab1.

loop at itab1 assigning field-symbol(<line>).
    write <line>.
endloop.

demonstrate how to concatenate two arrays in the given language, or in the case of ABAP, how to use internal tables as an alternative to arrays. This is applicable for ABAP version 7.40 and above.


REPORT morse_code.
TYPES: BEGIN OF y_morse_code,
         letter TYPE string,
         code   TYPE string,
       END OF y_morse_code,
       ty_morse_code TYPE STANDARD TABLE OF y_morse_code WITH EMPTY KEY.

cl_demo_output=>new(
          )->begin_section( |Morse Code|
          )->write( REDUCE stringtab( LET words = VALUE stringtab( ( |sos|                 )
                                                                   ( |   Hello     World!| )
                                                                   ( |Rosetta Code|        ) )
                                          morse_code = VALUE ty_morse_code( ( letter = 'A'   code = '.-     ' )
                                                                            ( letter = 'B'   code = '-...   ' )
                                                                            ( letter = 'C'   code = '-.-.   ' )
                                                                            ( letter = 'D'   code = '-..    ' )
                                                                            ( letter = 'E'   code = '.      ' )
                                                                            ( letter = 'F'   code = '..-.   ' )
                                                                            ( letter = 'G'   code = '--.    ' )
                                                                            ( letter = 'H'   code = '....   ' )
                                                                            ( letter = 'I'   code = '..     ' )
                                                                            ( letter = 'J'   code = '.---   ' )
                                                                            ( letter = 'K'   code = '-.-    ' )
                                                                            ( letter = 'L'   code = '.-..   ' )
                                                                            ( letter = 'M'   code = '--     ' )
                                                                            ( letter = 'N'   code = '-.     ' )
                                                                            ( letter = 'O'   code = '---    ' )
                                                                            ( letter = 'P'   code = '.--.   ' )
                                                                            ( letter = 'Q'   code = '--.-   ' )
                                                                            ( letter = 'R'   code = '.-.    ' )
                                                                            ( letter = 'S'   code = '...    ' )
                                                                            ( letter = 'T'   code = '-      ' )
                                                                            ( letter = 'U'   code = '..-    ' )
                                                                            ( letter = 'V'   code = '...-   ' )
                                                                            ( letter = 'W'   code = '.-   - ' )
                                                                            ( letter = 'X'   code = '-..-   ' )
                                                                            ( letter = 'Y'   code = '-.--   ' )
                                                                            ( letter = 'Z'   code = '--..   ' )
                                                                            ( letter = '0'   code = '-----  ' )
                                                                            ( letter = '1'   code = '.----  ' )
                                                                            ( letter = '2'   code = '..---  ' )
                                                                            ( letter = '3'   code = '...--  ' )
                                                                            ( letter = '4'   code = '....-  ' )
                                                                            ( letter = '5'   code = '.....  ' )
                                                                            ( letter = '6'   code = '-....  ' )
                                                                            ( letter = '7'   code = '--...  ' )
                                                                            ( letter = '8'   code = '---..  ' )
                                                                            ( letter = '9'   code = '----.  ' )
                                                                            ( letter = ''''  code = '.----. ' )
                                                                            ( letter = ':'   code = '---... ' )
                                                                            ( letter = ','   code = '--..-- ' )
                                                                            ( letter = '-'   code = '-....- ' )
                                                                            ( letter = '('   code = '-.--.- ' )
                                                                            ( letter = '.'   code = '.-.-.- ' )
                                                                            ( letter = '?'   code = '..--.. ' )
                                                                            ( letter = ';'   code = '-.-.-. ' )
                                                                            ( letter = '/'   code = '-..-.  ' )
                                                                            ( letter = '_'   code = '..--.- ' )
                                                                            ( letter = ')'   code = '---..  ' )
                                                                            ( letter = '='   code = '-...-  ' )
                                                                            ( letter = '@'   code = '.--.-. ' )
                                                                            ( letter = '\'   code = '.-..-. ' )
                                                                            ( letter = '+'   code = '.-.-.  ' )
                                                                            ( letter = ' '   code = '/'       ) )
                                      IN INIT word_coded_tab TYPE stringtab
                                          FOR word IN words
                                         NEXT word_coded_tab = VALUE #( BASE word_coded_tab ( REDUCE string( INIT word_coded TYPE string
                                                                                FOR index = 1 UNTIL index > strlen( word )
                                                                                LET _morse_code = VALUE #( morse_code[ letter = COND #( WHEN index = 1 THEN to_upper( word(index) )
                                                                                ELSE LET prev = index - 1 IN to_upper( word+prev(1) ) ) ]-code OPTIONAL )
                                                                                IN NEXT word_coded = |{ word_coded } { _morse_code }| ) ) ) )
          )->display( ).

<output> convert a given string into audible Morse code and send it to an audio device such as a PC speaker. It either ignores unknown characters or indicates them with a different pitch. </output>


REPORT z_rosetta_abc.

" Type declaration for blocks of letters
TYPES: BEGIN OF block,
         s1 TYPE char1,
         s2 TYPE char1,
       END OF block,

       blocks_table TYPE STANDARD TABLE OF block.

DATA: blocks TYPE blocks_table.

CLASS word_maker DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      can_make_word
        IMPORTING word          TYPE string
                  letter_blocks TYPE blocks_table
        RETURNING VALUE(found)  TYPE abap_bool.
ENDCLASS.

CLASS word_maker IMPLEMENTATION.
  METHOD can_make_word.

    " Create a reader stream that reads 1 character at a time
    DATA(reader) = NEW cl_abap_string_c_reader( word ).

    DATA(blocks) = letter_blocks.

    WHILE reader->data_available( ).

      DATA(ch) = to_upper( reader->read( 1 ) ).
      found = abap_false.

      LOOP AT blocks REFERENCE INTO DATA(b).
        IF ch = b->s1 OR ch = b->s2.
          found = abap_true.
          DELETE blocks INDEX sy-tabix.
          EXIT. " the inner loop once a character is found
        ENDIF.
      ENDLOOP.

      " If a character could not be found, stop looking further
      IF found = abap_false.
        RETURN.
      ENDIF.
    ENDWHILE.

  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  blocks = VALUE #( ( s1 = 'B' s2 = 'O' ) ( s1 = 'X' s2 = 'K' )
                    ( s1 = 'D' s2 = 'Q' ) ( s1 = 'C' s2 = 'P' )
                    ( s1 = 'N' s2 = 'A' ) ( s1 = 'G' s2 = 'T' )
                    ( s1 = 'R' s2 = 'E' ) ( s1 = 'T' s2 = 'G' )
                    ( s1 = 'Q' s2 = 'D' ) ( s1 = 'F' s2 = 'S' )
                    ( s1 = 'J' s2 = 'W' ) ( s1 = 'H' s2 = 'U' )
                    ( s1 = 'V' s2 = 'I' ) ( s1 = 'A' s2 = 'N' )
                    ( s1 = 'O' s2 = 'B' ) ( s1 = 'E' s2 = 'R' )
                    ( s1 = 'F' s2 = 'S' ) ( s1 = 'L' s2 = 'Y' )
                    ( s1 = 'P' s2 = 'C' ) ( s1 = 'Z' s2 = 'M' )
                  ).

  WRITE:/ COND string( WHEN word_maker=>can_make_word( word = 'A'        letter_blocks = blocks ) = abap_true THEN 'True' ELSE 'False' ).
  WRITE:/ COND string( WHEN word_maker=>can_make_word( word = 'BARK'     letter_blocks = blocks ) = abap_true THEN 'True' ELSE 'False' ).
  WRITE:/ COND string( WHEN word_maker=>can_make_word( word = 'BOOK'     letter_blocks = blocks ) = abap_true THEN 'True' ELSE 'False' ).
  WRITE:/ COND string( WHEN word_maker=>can_make_word( word = 'TREAT'    letter_blocks = blocks ) = abap_true THEN 'True' ELSE 'False' ).
  WRITE:/ COND string( WHEN word_maker=>can_make_word( word = 'COMMON'   letter_blocks = blocks ) = abap_true THEN 'True' ELSE 'False' ).
  WRITE:/ COND string( WHEN word_maker=>can_make_word( word = 'SQUAD'    letter_blocks = blocks ) = abap_true THEN 'True' ELSE 'False' ).
  WRITE:/ COND string( WHEN word_maker=>can_make_word( word = 'CONFUSE'  letter_blocks = blocks ) = abap_true THEN 'True' ELSE 'False' ).

"Output: The code defines a function that checks if a given word can be spelled using a specific collection of ABC blocks. Each block contains two letters and can only be used once. The function is case-insensitive and returns a boolean value based on whether or not the word can be formed."


fn main() {
    let mut stack = Vec::new();
    stack.push("Element1");
    stack.push("Element2");
    stack.push("Element3");

    assert_eq!(Some(&"Element3"), stack.last());
    assert_eq!(Some("Element3"), stack.pop());
    assert_eq!(Some("Element2"), stack.pop());
    assert_eq!(Some("Element1"), stack.pop());
    assert_eq!(None, stack.pop());
}

type Link<T> = Option<Box<Frame<T>>>;

pub struct Stack<T> {
    head: Link<T>,
}
struct Frame<T> {
    elem: T,
    next: Link<T>,
}

/// Iterate by value (consumes list)
pub struct IntoIter<T>(Stack<T>);
impl<T> Iterator for IntoIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.pop()
    }
}

/// Iterate by immutable reference
pub struct Iter<'a, T: 'a> {
    next: Option<&'a Frame<T>>,
}
impl<'a, T> Iterator for Iter<'a, T> { // Iterate by immutable reference
    type Item = &'a T;
    fn next(&mut self) -> Option<Self::Item> {
        self.next.take().map(|frame| {
            self.next = frame.next.as_ref().map(|frame| &**frame);
            &frame.elem
        })
    }
}

/// Iterate by mutable reference
pub struct IterMut<'a, T: 'a> {
    next: Option<&'a mut Frame<T>>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;
    fn next(&mut self) -> Option<Self::Item> {
        self.next.take().map(|frame| {
            self.next = frame.next.as_mut().map(|frame| &mut **frame);
            &mut frame.elem
        })
    }
}

impl<T> Stack<T> {
    /// Return new, empty stack
    pub fn new() -> Self {
        Stack { head: None }
    }

    /// Add element to top of the stack
    pub fn push(&mut self, elem: T) {
        let new_frame = Box::new(Frame {
            elem: elem,
            next: self.head.take(),
        });
        self.head = Some(new_frame);
    }

    /// Remove element from top of stack, returning the value
    pub fn pop(&mut self) -> Option<T> {
        self.head.take().map(|frame| {
            let frame = *frame;
            self.head = frame.next;
            frame.elem
        })
    }

    /// Get immutable reference to top element of the stack
    pub fn peek(&self) -> Option<&T> {
        self.head.as_ref().map(|frame| &frame.elem)
    }

    /// Get mutable reference to top element on the stack
    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.head.as_mut().map(|frame| &mut frame.elem)
    }

    /// Iterate over stack elements by value
    pub fn into_iter(self) -> IntoIter<T> {
        IntoIter(self)
    }

    /// Iterate over stack elements by immutable reference
    pub fn iter<'a>(&'a self) -> Iter<'a,T> {
        Iter { next: self.head.as_ref().map(|frame| &**frame) }
    }

    /// Iterate over stack elements by mutable reference
    pub fn iter_mut(&mut self) -> IterMut<T> {
        IterMut { next: self.head.as_mut().map(|frame| &mut **frame) }
    }
}

// The Drop trait tells the compiler how to free an object after it goes out of scope.
// By default, the compiler would do this recursively which *could* blow the stack for
// extraordinarily long lists. This simply tells it to do it iteratively.
impl<T> Drop for Stack<T> {
    fn drop(&mut self) {
        let mut cur_link = self.head.take();
        while let Some(mut boxed_frame) = cur_link {
            cur_link = boxed_frame.next.take();
        }
    }
}

implement a stack data structure that supports basic operations such as push (adding an element to the top of the stack), pop (removing the topmost element from the stack and returning it), and empty (checking if the stack contains no elements). The stack follows a last in, first out (LIFO) access policy. It can be implemented using a vector or a singly-linked list.


fn main() {
    let mut prev = 0;
    // Rust needs this type hint for the checked_add method
    let mut curr = 1usize;

    while let Some(n) = curr.checked_add(prev) {
        prev = curr;
        curr = n;
        println!("{}", n);
    }
}
use std::mem;
fn main() {
    fibonacci(0,1);
}

fn fibonacci(mut prev: usize, mut curr: usize) {
    mem::swap(&mut prev, &mut curr);
    if let Some(n) = curr.checked_add(prev) {
        println!("{}", n);
        fibonacci(prev, n);
    }
}
fn fib(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        n => fib(n - 1) + fib(n - 2),
    }
}
fn fib_tail_recursive(nth: usize) -> usize {
  fn fib_tail_iter(n: usize, prev_fib: usize, fib: usize) -> usize {
    match n {
      0 => prev_fib,
      n => fib_tail_iter(n - 1, fib, prev_fib + fib),
    }
  }
  fib_tail_iter(nth, 0, 1)
}
fn main() {
    for num in fibonacci_sequence() {
        println!("{}", num);
    }
}

fn fibonacci_sequence() -> impl Iterator<Item = u64> {
    let sqrt_5 = 5.0f64.sqrt();
    let p = (1.0 + sqrt_5) / 2.0;
    let q = 1.0 / p;
    // The range is sufficient up to 70th Fibonacci number
    (0..1).chain((1..70).map(move |n| ((p.powi(n) + q.powi(n)) / sqrt_5 + 0.5) as u64))
}

use std::mem;

struct Fib {
    prev: usize,
    curr: usize,
}

impl Fib {
    fn new() -> Self {
        Fib {prev: 0, curr: 1}
    }
}

impl Iterator for Fib {
    type Item = usize;
    fn next(&mut self) -> Option<Self::Item>{
        mem::swap(&mut self.curr, &mut self.prev);
        self.curr.checked_add(self.prev).map(|n| {
            self.curr = n;
            n
        })
    }
}

fn main() {
    for num in Fib::new() {
        println!("{}", num);
    }
}

fn main() {
    std::iter::successors(Some((1u128, 0)), |&(a, b)| a.checked_add(b).map(|s| (b, s)))
        .for_each(|(_, u)| println!("{}", u));
}

The code defines a function to generate the nth Fibonacci number, which can be either iterative or recursive. It optionally supports negative n values by using an inverse of the positive definition. The function utilizes idiomatic Rust iterators, although they might be overkill for this simple problem.


fn main() {
    println!("new vec filtered: ");
    let nums: Vec<i32> = (1..20).collect();
    let evens: Vec<i32> = nums.iter().cloned().filter(|x| x % 2 == 0).collect();
    println!("{:?}", evens);

    // Filter an already existing vector
    println!("original vec filtered: ");
    let mut nums: Vec<i32> = (1..20).collect();
    nums.retain(|x| x % 2 == 0);
    println!("{:?}", nums);
}

select certain elements from an array into a new array in a generic way. Specifically, it selects all even numbers from an array. Optionally, it can also filter destructively by modifying the original array instead of creating a new one.


let s = "abc文字化けdef";
let n = 2;
let m = 3;

    // Print 3 characters starting at index 2 (c文字)
println!("{}", s.chars().skip(n).take(m).collect::<String>());

    // Print all characters starting at index 2 (c文字化けdef)
println!("{}", s.chars().skip(n).collect::<String>());

    // Print all characters except the last (abc文字化けde)
println!("{}", s.chars().rev().skip(1).collect::<String>());

    // Print 3 characters starting with 'b' (bc文)
let cpos = s.find('b').unwrap();
println!("{}", s[cpos..].chars().take(m).collect::<String>());

    // Print 3 characters starting with "けd" (けde)
let spos = s.find("けd").unwrap();
println!("{}", s[spos..].chars().take(m).collect::<String>());

- Extracts a substring starting from the nth character of a specific length m.
- Extracts a substring starting from the nth character up to the end of the string.
- Returns the entire string excluding the last character.
- Extracts a substring starting from a known character within the string of length m.
- Extracts a substring starting from a known substring within the string of length m.
- Supports any valid Unicode code point, including those in the Basic Multilingual Plane or above it.
- References logical characters (code points), not 8-bit code units for UTF-8 or 16-bit code units for UTF-16.
- Does not necessarily support all Unicode characters for other encodings like 8-bit ASCII, or EUC-JP.


let mut buffer = b"abcdef".to_vec();
buffer.reverse();
assert_eq!(buffer, b"fedcba");

let output: String = "一二三四五六七八九十".chars().rev().collect();
assert_eq!(output, "十九八七六五四三二一");

let output: String = "as⃝df̅".chars().rev().collect();
assert_ne!(output, "f̅ds⃝a"); // should be this
assert_eq!(output, "̅fd⃝sa");

use unicode_segmentation::UnicodeSegmentation;

let output: String = "as⃝df̅".graphemes(true).rev().collect();
assert_eq!(output, "f̅ds⃝a");

The code takes an input string and reverses it. It also ensures the preservation of Unicode combining characters during the reversal process. The code handles the reversal of ASCII byte-slice in-place, Unicode scalar values, and graphemes clusters, which accounts for combining marks. The reversal of graphemes clusters is facilitated by the unicode-segmentation crate.


use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::usize;

struct Grid<T> {
    nodes: Vec<Node<T>>,
}

struct Node<T> {
    data: T,
    edges: Vec<(usize,usize)>,
}

#[derive(Copy, Clone, Eq, PartialEq)]
struct State {
    node: usize,
    cost: usize,
}

// Manually implement Ord so we get a min-heap instead of a max-heap
impl Ord for State {
    fn cmp(&self, other: &Self) -> Ordering {
        other.cost.cmp(&self.cost)
    }
}

impl PartialOrd for State {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

type WeightedEdge = (usize, usize, usize);

impl<T> Grid<T> {
    fn new() -> Self {
        Grid { nodes: Vec::new() }
    }

    fn add_node(&mut self, data: T) -> usize {
        let node = Node {
            edges: Vec::new(),
            data: data,
        };
        self.nodes.push(node);
        self.nodes.len() - 1
    }

    fn create_edges<'a, I>(&mut self, iterator: I) where I: IntoIterator<Item=&'a WeightedEdge> {
        for &(start,end,weight) in iterator.into_iter() {
            self.nodes[start].edges.push((end,weight));
            self.nodes[end].edges.push((start,weight));
        }

    }

    fn find_path(&self, start: usize, end: usize) -> Option<(Vec<usize>, usize)> {
        let mut dist = vec![(usize::MAX, None); self.nodes.len()];

        let mut heap = BinaryHeap::new();
        dist[start] = (0, None);
        heap.push(State {
            node: start,
            cost: 0,
        });

        while let Some(State { node, cost }) = heap.pop() {
            if node == end {
                let mut path = Vec::with_capacity(dist.len() / 2);
                let mut current_dist = dist[end];
                path.push(end);
                while let Some(prev) = current_dist.1 {
                    path.push(prev);
                    current_dist = dist[prev];
                }
                path.reverse();
                return Some((path, cost));
            }

            if cost > dist[node].0 {
                continue;
            }
            for edge in &self.nodes[node].edges {
                let next = State {
                    node: edge.0,
                    cost: cost + edge.1,
                };
                if next.cost < dist[next.node].0 {
                    dist[next.node] = (next.cost, Some(node));
                    heap.push(next);
                }
            }
        }
        None
    }
}

fn main() {
    let mut grid = Grid::new();
    let (a,b,c,d,e,f) = (grid.add_node("a"), grid.add_node("b"),
                         grid.add_node("c"), grid.add_node("d"),
                         grid.add_node("e"), grid.add_node("f"));

    grid.create_edges(&[
        (a,b,7) ,(a,c,9) ,(a,f,14),
        (b,c,10),(b,d,15),(c,d,11),
        (c,f,2) ,(d,e,6) ,(e,f,9) ,
    ]);

    let (path, cost) = grid.find_path(a,e).unwrap();

    print!("{}", grid.nodes[path[0]].data);
    for i in path.iter().skip(1) {
        print!(" -> {}", grid.nodes[*i].data);
    }
    println!("\nCost: {}", cost);

}

The code implements Dijkstra's algorithm to find the shortest path from a single source to all other vertices in a given graph. The graph is represented using an adjacency list. The algorithm starts from a given node, finds the path with the lowest cost to every other node, and outputs a set of edges depicting these shortest paths. The code also includes functionality to interpret the output and display the shortest path from the starting node to specific nodes.