/* ARM assembly AARCH64 Raspberry PI 3B or android 64 bits */
/*  program abelianSum64.s   */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
.equ MAXI, 3

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessValue:        .asciz "@ "
szMessAdd1:         .asciz "Add sandpile 1 to sandpile 2  \n"
szMessAdd2:         .asciz "Add sandpile 2 to sandpile 1  \n"
szMessAdd2A:        .asciz "Add sandpile 2A to sandpile result  \n"
szMessAdd3:         .asciz "Add sandpile 3 to sandpile 3ID  \n"
szMessAdd3ID:       .asciz "Add sandpile 3ID to sandpile 3ID  \n"

szCarriageReturn:   .asciz "\n"

qSandPile1:    .quad 1,2,0
               .quad 2,1,1
               .quad 0,1,3

qSandPile2:    .quad 2,1,3
               .quad 1,0,1
               .quad 0,1,0

qSandPile2A:    .quad 1,0,0
               .quad 0,0,0
               .quad 0,0,0

qSandPile3:    .quad 3,3,3
               .quad 3,3,3
               .quad 3,3,3

qSandPile3ID:  .quad 2,1,2
               .quad 1,0,1
               .quad 2,1,2
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:        .skip 24
qSandPilex1:      .skip 8 * MAXI * MAXI
qSandPilex2:      .skip 8 * MAXI * MAXI
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                            // entry of program

    ldr x0,qAdrqSandPile1        // sandpile1 address
    ldr x1,qAdrqSandPile2        // sandpile2 address
    ldr x2,qAdrqSandPilex1       // sandpile result address
    bl addSandPile

    ldr x0,qAdrszMessAdd1        // display message
    bl affichageMess
    ldr x0,qAdrqSandPilex1       // display sandpile
    bl displaySandPile

    ldr x0,qAdrqSandPile2        // sandpile2 address
    ldr x1,qAdrqSandPile1        // sandpile1 address
    ldr x2,qAdrqSandPilex1       // sandpile result address
    bl addSandPile

    ldr x0,qAdrszMessAdd2
    bl affichageMess
    ldr x0,qAdrqSandPilex1
    bl displaySandPile

    ldr x0,qAdrqSandPilex1        // sandpile1 address
    ldr x1,qAdrqSandPile2A        // sandpile2A address
    ldr x2,qAdrqSandPilex2        // sandpile result address
    bl addSandPile

    ldr x0,qAdrszMessAdd2A
    bl affichageMess
    ldr x0,qAdrqSandPilex2
    bl displaySandPile

    ldr x0,qAdrqSandPile3          // sandpile3 address
    ldr x1,qAdrqSandPile3ID        // sandpile3ID address
    ldr x2,qAdrqSandPilex2         // sandpile result address
    bl addSandPile

    ldr x0,qAdrszMessAdd3
    bl affichageMess
    ldr x0,qAdrqSandPilex2
    bl displaySandPile

    ldr x0,qAdrqSandPile3ID        // sandpile3 address
    ldr x1,qAdrqSandPile3ID        // sandpile3ID address
    ldr x2,qAdrqSandPilex2         // sandpile result address
    bl addSandPile

    ldr x0,qAdrszMessAdd3ID
    bl affichageMess
    ldr x0,qAdrqSandPilex2
    bl displaySandPile
100:                               // standard end of the program
    mov x0, #0                     // return code
    mov x8, #EXIT                  // request to exit program
    svc #0                         // perform the system call

qAdrszCarriageReturn:     .quad szCarriageReturn
qAdrsZoneConv:            .quad sZoneConv
qAdrszMessAdd1:           .quad szMessAdd1
qAdrszMessAdd2:           .quad szMessAdd2
qAdrszMessAdd2A:          .quad szMessAdd2A
qAdrszMessAdd3:           .quad szMessAdd3
qAdrszMessAdd3ID:         .quad szMessAdd3ID
qAdrqSandPile1:           .quad qSandPile1
qAdrqSandPilex1:          .quad qSandPilex1
qAdrqSandPilex2:          .quad qSandPilex2
qAdrqSandPile2:           .quad qSandPile2
qAdrqSandPile2A:          .quad qSandPile2A
qAdrqSandPile3:           .quad qSandPile3
qAdrqSandPile3ID:         .quad qSandPile3ID
/***************************************************/
/*     add two  sandpile               */
/***************************************************/
// x0 contains address to sandpile 1
// x1 contains address to sandpile 2
// x2 contains address to sandpile result
addSandPile:
    stp x1,lr,[sp,-16]!       // save  registres
    stp x2,x3,[sp,-16]!       // save  registres
    stp x4,x5,[sp,-16]!       // save  registres
    stp x6,x7,[sp,-16]!       // save  registres
    mov x6,x1                 // save addresse sandpile2
    mov x1,x2                 // and copy sandpile 1 to sandpile result
    bl copySandPile
    mov x0,x2                 // sanspile result
    mov x2,#0                 // indice y
    mov x4,#MAXI
1:
    mov x1,#0                  // indice x
2:
    madd x5,x2,x4,x1           // compute offset
    ldr x7,[x0,x5,lsl #3]      // load value at pos x,y sanspile result
    ldr x3,[x6,x5,lsl #3]      // load value at pos x,y sandpile 2
    add x7,x7,x3
    str x7,[x0,x5,lsl #3]      // store sum on sandpile result
    bl avalancheRisk
    add x1,x1,#1
    cmp x1,#MAXI
    blt 2b
    add x2,x2,#1
    cmp x2,#MAXI
    blt 1b
100:
    ldp x6,x7,[sp],16         // restaur des  2 registres
    ldp x4,x5,[sp],16         // restaur des  2 registres
    ldp x2,x3,[sp],16         // restaur des  2 registres
    ldp x1,lr,[sp],16         // restaur des  2 registres
    ret
/***************************************************/
/*     copy sandpile                               */
/***************************************************/
// x0 contains address to sandpile
// x1 contains address to sandpile result
copySandPile:
    stp x1,lr,[sp,-16]!         // save  registres
    stp x2,x3,[sp,-16]!         // save  registres
    stp x4,x5,[sp,-16]!         // save  registres
    stp x6,x7,[sp,-16]!         // save  registres
    mov x2,#0                   // indice y
    mov x3,#MAXI
1:
    mov x4,#0                   // indice x
2:
    madd x5,x2,x3,x4            // compute offset
    ldr x6,[x0,x5,lsl #3]       // load value at pos x,y sanspile
    str x6,[x1,x5,lsl #3]       // store value at pos x,y sandpile result
    add x4,x4,#1
    cmp x4,#MAXI
    blt 2b
    add x2,x2,#1
    cmp x2,#MAXI
    blt 1b
100:
    ldp x6,x7,[sp],16          // restaur des  2 registres
    ldp x4,x5,[sp],16          // restaur des  2 registres
    ldp x2,x3,[sp],16          // restaur des  2 registres
    ldp x1,lr,[sp],16          // restaur des  2 registres
    ret
/***************************************************/
/*     display  sandpile               */
/***************************************************/
// x0 contains address to sandpile
displaySandPile:
    stp x1,lr,[sp,-16]!         // save  registres
    stp x2,x3,[sp,-16]!         // save  registres
    stp x4,x5,[sp,-16]!         // save  registres
    stp x6,x7,[sp,-16]!         // save  registres
    mov x6,x0
    mov x3,#0                   // indice y
    mov x4,#MAXI
1:
    mov x2,#0                   // indice x
2:
    madd x5,x3,x4,x2            // compute offset
    ldr x0,[x6,x5,lsl #3]       // load value at pos x,y
    ldr x1,qAdrsZoneConv
    bl conversion10             // call decimal conversion
    add x1,x1,#1
    mov x7,#0
    strb w7,[x1,x0]
    ldr x0,qAdrszMessValue
    ldr x1,qAdrsZoneConv        // insert value conversion in message
    bl strInsertAtCharInc
    bl affichageMess
    add x2,x2,#1
    cmp x2,#MAXI
    blt 2b
    ldr x0,qAdrszCarriageReturn
    bl affichageMess
    add x3,x3,#1
    cmp x3,#MAXI
    blt 1b

100:
    ldp x6,x7,[sp],16          // restaur des  2 registres
    ldp x4,x5,[sp],16          // restaur des  2 registres
    ldp x2,x3,[sp],16          // restaur des  2 registres
    ldp x1,lr,[sp],16          // restaur des  2 registres
    ret
qAdrszMessValue:       .quad szMessValue
/***************************************************/
/*     avalanche risk              */
/***************************************************/
// x0 contains address to sanspile
// x1 contains position x
// x2 contains position y
avalancheRisk:
    stp x1,lr,[sp,-16]!         // save  registres
    stp x2,x3,[sp,-16]!         // save  registres
    stp x4,x5,[sp,-16]!         // save  registres
    mov x3,#MAXI
    madd x4,x3,x2,x1
    ldr x5,[x0,x4,lsl #3]
1:
    cmp x5,#4                   // 4 grains ?
    blt 100f
    sub x5,x5,#4                   // yes sustract
    str x5,[x0,x4,lsl #3]
    cmp x1,#MAXI-1              // right position ok ?
    beq 2f
    add x1,x1,#1                   // yes
    bl add1Sand                 // add 1 grain
    bl avalancheRisk                  // and compute new pile
    sub x1,x1,#1
2:
    cmp x1,#0                   // left position ok ?
    beq 3f
    sub x1,x1,#1
    bl add1Sand
    bl avalancheRisk
    add x1,x1,#1
3:
    cmp x2,#0                   // higt position ok ?
    beq 4f
    sub x2,x2,#1
    bl add1Sand
    bl avalancheRisk
    add x2,x2,#1
4:
    cmp x2,#MAXI-1               // low position ok ?
    beq 5f
    add x2,x2,#1
    bl add1Sand
    bl avalancheRisk
    sub x2,x2,#1
5:
   ldr x5,[x0,x4,lsl #3]       // reload value
   b 1b                        // and loop
100:
    ldp x4,x5,[sp],16          // restaur des  2 registres
    ldp x2,x3,[sp],16          // restaur des  2 registres
    ldp x1,lr,[sp],16          // restaur des  2 registres
    ret
/***************************************************/
/*     add 1 grain of sand              */
/***************************************************/
// x0 contains address to sanspile
// x1 contains position x
// x2 contains position y
add1Sand:
    stp x3,lr,[sp,-16]!         // save  registres
    stp x4,x5,[sp,-16]!         // save  registres
    mov x3,#MAXI
    madd x4,x3,x2,x1
    ldr x5,[x0,x4,lsl #3]     // load value at pos x,y
    add x5,x5,#1
    str x5,[x0,x4,lsl #3]     // and store
100:
    ldp x4,x5,[sp],16          // restaur des  2 registres
    ldp x3,lr,[sp],16          // restaur des  2 registres
    ret
/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"


/* ARM assembly Raspberry PI  or android 32 bits */
/*  program abelianSum.s   */

/* REMARK 1 : this program use routines in a include file
   see task Include a file language arm assembly
   for the routine affichageMess conversion10
   see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes                       */
/************************************/
.include "../constantes.inc"
.equ MAXI, 3

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessValue:        .asciz "@ "
szMessAdd1:         .asciz "Add sandpile 1 to sandpile 2  \n"
szMessAdd2:         .asciz "Add sandpile 2 to sandpile 1  \n"
szMessAdd2A:        .asciz "Add sandpile 2A to sandpile result  \n"
szMessAdd3:         .asciz "Add sandpile 3 to sandpile 3ID  \n"
szMessAdd3ID:       .asciz "Add sandpile 3ID to sandpile 3ID  \n"

szMessFin:          .asciz "End display :\n"
szCarriageReturn:   .asciz "\n"

iSandPile1:    .int 1,2,0
               .int 2,1,1
               .int 0,1,3

iSandPile2:    .int 2,1,3
               .int 1,0,1
               .int 0,1,0

iSandPile2A:    .int 1,0,0
               .int 0,0,0
               .int 0,0,0

iSandPile3:    .int 3,3,3
               .int 3,3,3
               .int 3,3,3

iSandPile3ID:  .int 2,1,2
               .int 1,0,1
               .int 2,1,2
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:        .skip 24
iSandPileR1:      .skip 4 * MAXI * MAXI
iSandPileR2:      .skip 4 * MAXI * MAXI
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                            @ entry of program

    ldr r0,iAdriSandPile1        @ sandpile1 address
    ldr r1,iAdriSandPile2        @ sandpile2 address
    ldr r2,iAdriSandPileR1       @ sandpile result address
    bl addSandPile

    ldr r0,iAdrszMessAdd1        @ display message
    bl affichageMess
    ldr r0,iAdriSandPileR1       @ display sandpile
    bl displaySandPile

    ldr r0,iAdriSandPile2        @ sandpile2 address
    ldr r1,iAdriSandPile1        @ sandpile1 address
    ldr r2,iAdriSandPileR1       @ sandpile result address
    bl addSandPile

    ldr r0,iAdrszMessAdd2
    bl affichageMess
    ldr r0,iAdriSandPileR1
    bl displaySandPile

    ldr r0,iAdriSandPileR1        @ sandpile1 address
    ldr r1,iAdriSandPile2A        @ sandpile2A address
    ldr r2,iAdriSandPileR2        @ sandpile result address
    bl addSandPile

    ldr r0,iAdrszMessAdd2A
    bl affichageMess
    ldr r0,iAdriSandPileR2
    bl displaySandPile

    ldr r0,iAdriSandPile3          @ sandpile3 address
    ldr r1,iAdriSandPile3ID        @ sandpile3ID address
    ldr r2,iAdriSandPileR2         @ sandpile result address
    bl addSandPile

    ldr r0,iAdrszMessAdd3
    bl affichageMess
    ldr r0,iAdriSandPileR2
    bl displaySandPile

    ldr r0,iAdriSandPile3ID        @ sandpile3 address
    ldr r1,iAdriSandPile3ID        @ sandpile3ID address
    ldr r2,iAdriSandPileR2         @ sandpile result address
    bl addSandPile

    ldr r0,iAdrszMessAdd3ID
    bl affichageMess
    ldr r0,iAdriSandPileR2
    bl displaySandPile
100:                               @ standard end of the program
    mov r0, #0                     @ return code
    mov r7, #EXIT                  @ request to exit program
    svc #0                         @ perform the system call

iAdrszCarriageReturn:     .int szCarriageReturn
iAdrsZoneConv:            .int sZoneConv
iAdrszMessFin:            .int szMessFin
iAdrszMessAdd1:           .int szMessAdd1
iAdrszMessAdd2:           .int szMessAdd2
iAdrszMessAdd2A:          .int szMessAdd2A
iAdrszMessAdd3:           .int szMessAdd3
iAdrszMessAdd3ID:         .int szMessAdd3ID
iAdriSandPile1:           .int iSandPile1
iAdriSandPileR1:          .int iSandPileR1
iAdriSandPileR2:          .int iSandPileR2
iAdriSandPile2:           .int iSandPile2
iAdriSandPile2A:          .int iSandPile2A
iAdriSandPile3:           .int iSandPile3
iAdriSandPile3ID:         .int iSandPile3ID
/***************************************************/
/*     add two  sandpile               */
/***************************************************/
// r0 contains address to sandpile 1
// r1 contains address to sandpile 2
// r2 contains address to sandpile result
addSandPile:
    push {r1-r7,lr}           @ save  registers
    mov r6,r1                 @ save addresse sandpile2
    mov r1,r2                 @ and copy sandpile 1 to sandpile result
    bl copySandPile
    mov r0,r2                 @ sanspile result
    mov r2,#0                 @ indice y
    mov r4,#MAXI
1:
    mov r1,#0                  @ indice x
2:
    mla r5,r2,r4,r1            @ compute offset
    ldr r7,[r0,r5,lsl #2]      @ load value at pos x,y sanspile result
    ldr r3,[r6,r5,lsl #2]      @ load value at pos x,y sandpile 2
    add r7,r3
    str r7,[r0,r5,lsl #2]      @ store sum on sandpile result
    bl avalancheRisk
    add r1,r1,#1
    cmp r1,#MAXI
    blt 2b
    add r2,r2,#1
    cmp r2,#MAXI
    blt 1b
100:
    pop {r1-r7,lr}             @ restaur registers
    bx lr                      @ return
/***************************************************/
/*     copy sandpile                               */
/***************************************************/
// r0 contains address to sandpile
// r1 contains address to sandpile result
copySandPile:
    push {r1-r6,lr}           @ save  registers
    mov r2,#0                 @ indice y
    mov r3,#MAXI
1:
    mov r4,#0                   @ indice x
2:
    mla r5,r2,r3,r4            @ compute offset
    ldr r6,[r0,r5,lsl #2]      @ load value at pos x,y sanspile
    str r6,[r1,r5,lsl #2]      @ store value at pos x,y sandpile result
    add r4,r4,#1
    cmp r4,#MAXI
    blt 2b
    add r2,r2,#1
    cmp r2,#MAXI
    blt 1b
100:
    pop {r1-r6,lr}             @ restaur registers
    bx lr                      @ return
/***************************************************/
/*     display  sandpile               */
/***************************************************/
// r0 contains address to sandpile
displaySandPile:
    push {r1-r6,lr}             @ save  registers
    mov r6,r0
    mov r3,#0                   @ indice y
    mov r4,#MAXI
1:
    mov r2,#0                   @ indice x
2:
    mul r5,r3,r4
    add r5,r2                   @ compute offset
    ldr r0,[r6,r5,lsl #2]       @ load value at pos x,y
    ldr r1,iAdrsZoneConv
    bl conversion10             @ call decimal conversion
    add r1,#1
    mov r7,#0
    strb r7,[r1,r0]
    ldr r0,iAdrszMessValue
    ldr r1,iAdrsZoneConv        @ insert value conversion in message
    bl strInsertAtCharInc
    bl affichageMess
    add r2,#1
    cmp r2,#MAXI
    blt 2b
    ldr r0,iAdrszCarriageReturn
    bl affichageMess
    add r3,#1
    cmp r3,#MAXI
    blt 1b

100:
    pop {r1-r6,lr}             @ restaur registers
    bx lr                      @ return
iAdrszMessValue:       .int szMessValue
/***************************************************/
/*     avalanche risk              */
/***************************************************/
// r0 contains address to sanspile
// r1 contains position x
// r2 contains position y
avalancheRisk:
    push {r1-r5,lr}             @ save  registers
    mov r3,#MAXI
    mul r4,r3,r2
    add r4,r1
    ldr r5,[r0,r4,lsl #2]
1:
    cmp r5,#4                   @ 4 grains ?
    blt 100f
    sub r5,#4                   @ yes sustract
    str r5,[r0,r4,lsl #2]
    cmp r1,#MAXI-1              @ right position ok ?
    beq 2f
    add r1,#1                   @ yes
    bl add1Sand                 @ add 1 grain
    bl avalancheRisk                  @ and compute new pile
    sub r1,#1
2:
    cmp r1,#0                   @ left position ok ?
    beq 3f
    sub r1,#1
    bl add1Sand
    bl avalancheRisk
    add r1,#1
3:
    cmp r2,#0                   @ higt position ok ?
    beq 4f
    sub r2,#1
    bl add1Sand
    bl avalancheRisk
    add r2,#1
4:
    cmp r2,#MAXI-1               @ low position ok ?
    beq 5f
    add r2,#1
    bl add1Sand
    bl avalancheRisk
    sub r2,#1
5:
   ldr r5,[r0,r4,lsl #2]       @ reload value
   b 1b                        @ and loop
100:
    pop {r1-r5,lr}             @ restaur registers
    bx lr                      @ return
/***************************************************/
/*     add 1 grain of sand              */
/***************************************************/
// r0 contains address to sanspile
// r1 contains position x
// r2 contains position y
add1Sand:
    push {r3-r5,lr}           @ save  registers
    mov r3,#MAXI
    mul r4,r3,r2
    add r4,r1                 @ compute offset
    ldr r5,[r0,r4,lsl #2]     @ load value at pos x,y
    add r5,#1
    str r5,[r0,r4,lsl #2]     @ and store
100:
    pop {r3-r5,lr}            @ restaur registers
    bx lr                     @ return
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../affichage.inc"


Class BaseState {
Private:
      x as double=1212, z1 as currency=1000, k$="ok"
      Module Err {
                  Module "Class.BaseState"
                  Error "not implement yet"
      }
}
Class AbstractOne {
Public:
      Group z {
            Value {
                  Link parent z1 to z1
                  =z1
            }
      }
      Function M(k as double) {
            .Err
      }
      Module AddCurrency (k as currency) {
            .Err
      }
      Function GetString$ {
            .Err
      }
Class:
      Module AbstractOne {
                  If Not Match("G") Then Exit
                  Read x
                  \\ combine x with This
                  This=x
      }
}
\\ create new group as K
K=AbstractOne(BaseState())
Try  ok {
      Print K.GetString$()
}
If Not ok Then Print Error$
\\ Now Add final functions/modules
Group k {
      Function Final M(k as double) {
            =.x*k
      }
      Module Final AddCurrency (k as currency) {
            .z1+=k
      }
      Function Final GetString$ {
            =.K$
      }
}
Print k.M(100), k.GetString$()
K.AddCurrency 50.12
Def ExpType$(x)=Type$(x)
Print k.z=1050.12, ExpType$(k.z), Type$(k.z) ' true, Currency, Group
\\ Now combine AbstractOne without new BaseState
\\ but because all functions are final in k, nothing combined
k=AbstractOne()
Print k.M(100), k.GetString$()
For k {
      \\ we can use For Object {} and a dot before members to get access
      Print .z=1050.12, ExpType$(.z), Type$(.z) ' true, Currency, Group
}


(* Define an interface, Foo, which requires that the functions Foo, Bar, and Baz be defined *)
InterfaceFooQ[obj_] := ValueQ[Foo[obj]] && ValueQ[Bar[obj]] && ValueQ[Baz[obj]];
PrintFoo[obj_] := Print["Object ", obj, " does not implement interface Foo."];
PrintFoo[obj_?InterfaceFooQ] := Print[
   "Foo: ", Foo[obj], "\n",
   "Bar: ", Bar[obj], "\n",
   "Baz: ", Baz[obj], "\n"];

(* Extend all integers with Interface Foo *)
Foo[x_Integer] := Mod[x, 2];
Bar[x_Integer] := Mod[x, 3];
Baz[x_Integer] := Mod[x, 5];

(* Extend a particular string with Interface Foo *)
Foo["Qux"] = "foo";
Bar["Qux"] = "bar";
Baz["Qux"] = "baz";

(* Print a non-interface object *)
PrintFoo[{"Some", "List"}];
(* And for an integer *)
PrintFoo[8];
(* And for the specific string *)
PrintFoo["Qux"];
(* And finally a non-specific string *)
PrintFoo["foobarbaz"]


:- module eq.
:- interface.

:- typeclass eq(T) where [
    pred (T::in) == (T::in) is semidet,
    pred (T::in) \= (T::in) is semidet
].

:- pred f(T::in) is semidet <= eq(T).

:- type foo
    --->    foo(
                x :: int,
                str :: string
            ).

:- instance eq(foo).

:- implementation.

f(X) :- X == X.

:- instance eq(foo) where [
    A == B :- (A^x = B^x, A^str = B^str),
    A \= B :- not A == B
].


Declare max(a,b)

If OpenConsole()
  Define a, i, x, y, maxlen
  Dim txt.s(0)
  Restore lines             ; Get address of the first data block
  Read.i  a
  ReDim txt(a)
  For i=0 To a              ; Read the raw data lines
    Read.s txt(i)
    txt(i)=Trim(txt(i),"$") ; Remove any bad '$' that may be useless in the end...
    x=max(CountString(txt(i),"$"),x)
  Next
  y=a
  Dim matrix.s(x,y)         ; Set up a nice matrix to work with, each word cleanly separated
  For x=0 To ArraySize(matrix(),1)
    For y=0 To ArraySize(matrix(),2)
      matrix(x,y)=StringField(txt(y),x+1,"$")
      maxlen=max(maxlen,Len(matrix(x,y)))
    Next
  Next
  If maxlen%2
    maxlen+1                ; Just to make sure that 'centered' output looks nice....
  EndIf

  PrintN(#CRLF$+"---- Right ----")
  For y=0 To ArraySize(matrix(),2)
    For x=0 To ArraySize(matrix(),1)
      Print(RSet(matrix(x,y),maxlen+1))
    Next
    PrintN("")
  Next

  PrintN(#CRLF$+"---- Left ----")
  For y=0 To ArraySize(matrix(),2)
    For x=0 To ArraySize(matrix(),1)
      Print(LSet(matrix(x,y),maxlen+1))
    Next
    PrintN("")
  Next

  PrintN(#CRLF$+"---- Center ----")
  For y=0 To ArraySize(matrix(),2)
    For x=0 To ArraySize(matrix(),1)
      a=maxlen-Len(matrix(x,y))
      Print(LSet(RSet(matrix(x,y),maxlen-a/2),maxlen))
    Next
    PrintN("")
  Next

  PrintN(#CRLF$+#CRLF$+"Press ENTER to quit."): Input()
  CloseConsole()
EndIf

Procedure max(x,y)
  If x>=y
    ProcedureReturn x
  Else
    ProcedureReturn y
  EndIf
EndProcedure

DataSection
lines:
  Data.i  5 ; e.g. 6-1 since first line is equal to 'zero'.
text:
  Data.s "Given$a$text$file$of$many$lines,$where$fields$within$a$line$"
  Data.s "are$delineated$by$a$single$'dollar'$character,$write$a$program"
  Data.s "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$"
  Data.s "column$are$separated$by$at$least$one$space."
  Data.s "Further,$allow$for$each$word$in$a$column$oo$be$either$left$"
  Data.s "justified,$right$justified,$or$center$justified$within$its$column."
EndDataSection


-- Works with Ada 2012

package Abelian_Sandpile is
   Limit : constant Integer := 4;

   type Sandpile is array (0 .. 2, 0 .. 2) of Natural with
      Default_Component_Value => 0;

   procedure Stabalize (Pile : in out Sandpile);
   function Is_Stable (Pile : in Sandpile) return Boolean;
   procedure Topple (Pile : in out Sandpile);
   function "+" (Left, Right : Sandpile) return Sandpile;
   procedure Print(PIle : in Sandpile);

end Abelian_Sandpile;


BEGIN # model Abelian sandpiles #
    # represents a sandpile #
    INT elements = 3;
    MODE SANDPILE = [ 1 : elements, 1 : elements ]INT;
    # returns TRUE if the sandpiles a and b have the same values, FALSE otherwise #
    OP = = ( SANDPILE a, b )BOOL:
    BEGIN
        BOOL result := TRUE;
        FOR i TO elements WHILE result DO
            FOR j TO elements WHILE ( result := a[ i, j ] = b[ i, j ] ) DO SKIP OD
        OD;
        result
    END # = # ;
    # returns TRUE if the sandpile s is stable, FALSE otherwise #
    OP STABLE = ( SANDPILE s )BOOL:
       BEGIN
           BOOL result := TRUE;
           FOR i TO elements WHILE result DO
               FOR j TO elements WHILE result := s[ i, j ] < 4 DO SKIP OD
           OD;
           result
       END # STABLE # ;
    # returns the sandpile s after avalanches #
    OP AVALANCHE = ( SANDPILE s )SANDPILE:
       BEGIN
           SANDPILE result := s;
           WHILE BOOL had avalanche := FALSE;
                 FOR i TO elements DO
                     FOR j TO elements DO
                         IF result[ i, j ] >= 4 THEN
                             # unstable pile #
                             had avalanche := TRUE;
                             result[ i, j ] -:= 4;
                             IF i > 1        THEN result[ i - 1, j     ] +:= 1 FI;
                             IF i < elements THEN result[ i + 1, j     ] +:= 1 FI;
                             IF j > 1        THEN result[ i,     j - 1 ] +:= 1 FI;
                             IF j < elements THEN result[ i,     j + 1 ] +:= 1 FI
                         FI
                     OD
                 OD;
                 had avalanche
           DO SKIP OD;
           result
       END # AVALANCHE # ;
    # returns the result of adding the sandpile b to a, handling avalanches #
    OP + = ( SANDPILE a, b )SANDPILE:
    BEGIN
        SANDPILE result;
        FOR i TO elements DO
            FOR j TO elements DO result[ i, j ] := a[ i, j ] + b[ i, j ] OD
        OD;
        # handle avalanches #
        AVALANCHE result
    END # + # ;
    # prints the sandpile s #
    PROC show sandpile = ( STRING title, SANDPILE s )VOID:
    BEGIN
        print( ( title, newline ) );
        FOR i TO elements DO
            FOR j TO elements DO
                print( ( " ", whole( s[ i, j ], 0 ) ) )
            OD;
            print( ( newline ) )
        OD
    END # show sandpile # ;
    # task test cases #
    SANDPILE us    = ( ( 4, 3, 3 )
                     , ( 3, 1, 2 )
                     , ( 0, 2, 3 )
                     );
    SANDPILE s1    = ( ( 1, 2, 0 )
                     , ( 2, 1, 1 )
                     , ( 0, 1, 3 )
                     );
    SANDPILE s2    = ( ( 2, 1, 3 )
                     , ( 1, 0, 1 )
                     , ( 0, 1, 0 )
                     );
    SANDPILE s3    = ( ( 3, 3, 3 )
                     , ( 3, 3, 3 )
                     , ( 3, 3, 3 )
                     );
    SANDPILE s3_id = ( ( 2, 1, 2 )
                     , ( 1, 0, 1 )
                     , ( 2, 1, 2 )
                     );
    SANDPILE t := us;
    WHILE NOT STABLE t DO
        show sandpile( "unstable:", t );
        t := AVALANCHE t
    OD;
    show sandpile( "stable: ", t );
    print( ( newline ) );
    show sandpile( "s1:", s1 );
    show sandpile( "s2:", s2 );
    show sandpile( "s1 + s2:", s1 + s2 );
    show sandpile( "s2 + s1:", s2 + s1 );
    print( ( newline ) );
    show sandpile( "s3:", s3 );
    show sandpile( "s3_id:", s3_id );
    print( ( newline ) );
    print( ( "s3 + s3_id = s3 is ", IF s3 + s3_id = s3 THEN "TRUE" ELSE "FALSE" FI, newline ) );
    show sandpile( "s3 + s3_id", s3 + s3_id );
    print( ( "s3_id + s3 = s3 is ", IF s3 + s3_id = s3 THEN "TRUE" ELSE "FALSE" FI, newline ) );
    show sandpile( "s3_id + s3", s3_id + s3 );
    show sandpile( "s3_id + s3_id:", s3_id + s3_id )

END


using System.Console;

namespace RosettaCode
{
    abstract class Fruit
    {
        abstract public Eat() : void;
        abstract public Peel() : void;

        virtual public Cut() : void      // an abstract class con contain a mixture of abstract and implemented methods
        {                                // the virtual keyword allows the method to be overridden by derivative classes
            WriteLine("Being cut.");
        }
    }

    interface IJuiceable
    {
        Juice() : void;           // interfaces contain only the signatures of methods
    }

    class Orange : Fruit, IJuiceable
    {
        public override Eat() : void     // implementations of abstract methods need to be marked override
        {
            WriteLine("Being eaten.");
        }

        public override Peel() : void
        {
            WriteLine("Being peeled.");
        }

        public Juice() : void
        {
            WriteLine("Being juiced.");
        }
    }
}


/* NetRexx */
options replace format comments java crossref symbols binary

-- -----------------------------------------------------------------------------
class RCAbstractType public final

method main(args = String[]) public constant

  say '  Testing' RCAbstractType.class.getSimpleName
  say '  Creating an object of type:' Concrete.class.getSimpleName
  conk = Concrete()
  say    'getClassName:'.right(20) conk.getClassName
  say    'getIfaceName:'.right(20) conk.getIfaceName
  say   'mustImplement:'.right(20) conk.mustImplement
  say    'canOverride1:'.right(20) conk.canOverride1
  say    'canOverride2:'.right(20) conk.canOverride2
  say 'callOverridden2:'.right(20) conk.callOverridden2

  return

-- -----------------------------------------------------------------------------
class RCAbstractType.Iface interface

ifaceName = RCAbstractType.Iface.class.getSimpleName

method getIfaceName() public returns String
method canOverride1() public returns String
method canOverride2() public returns String

-- -----------------------------------------------------------------------------
class RCAbstractType.Abstraction abstract implements RCAbstractType.Iface

properties inheritable
  className = String

method Abstraction() public
  setClassName(this.getClass.getSimpleName)
  return

method mustImplement() public abstract returns String

method getClassName() public returns String
  return className

method setClassName(nm = String) public
  className = nm
  return

method getIfaceName() public returns String
  return RCAbstractType.Iface.ifaceName

method canOverride1() public returns String
  return 'In' RCAbstractType.Abstraction.class.getSimpleName'.canOverride1'

method canOverride2() public returns String
  return 'In' RCAbstractType.Abstraction.class.getSimpleName'.canOverride2'

-- -----------------------------------------------------------------------------
class RCAbstractType.Concrete extends RCAbstractType.Abstraction

method Concrete() public
  super()
  return

method mustImplement() public returns String
  return 'In' RCAbstractType.Concrete.class.getSimpleName'.mustImplement'

method canOverride2() public returns String
  return 'In' RCAbstractType.Concrete.class.getSimpleName'.canOverride2'

method callOverridden2() public returns String
  return super.canOverride2


from itertools import zip_longest

txt = """Given$a$txt$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."""

parts = [line.rstrip("$").split("$") for line in txt.splitlines()]
widths = [max(len(word) for word in col)
          for col in zip_longest(*parts, fillvalue='')]

for justify in "<_Left ^_Center >_Right".split():
    j, jtext = justify.split('_')
    print(f"{jtext} column-aligned output:\n")
    for line in parts:
        print(' '.join(f"{wrd:{j}{wdth}}" for wdth, wrd in zip(widths, line)))
    print("- " * 52)


#include <algorithm>
#include <array>
#include <cassert>
#include <initializer_list>
#include <iostream>

constexpr size_t sp_rows = 3;
constexpr size_t sp_columns = 3;
constexpr size_t sp_cells = sp_rows * sp_columns;
constexpr int sp_limit = 4;

class abelian_sandpile {
    friend std::ostream& operator<<(std::ostream&, const abelian_sandpile&);

public:
    abelian_sandpile();
    explicit abelian_sandpile(std::initializer_list<int> init);
    void stabilize();
    bool is_stable() const;
    void topple();
    abelian_sandpile& operator+=(const abelian_sandpile&);
    bool operator==(const abelian_sandpile&);

private:
    int& cell_value(size_t row, size_t column) {
        return cells_[cell_index(row, column)];
    }
    static size_t cell_index(size_t row, size_t column) {
        return row * sp_columns + column;
    }
    static size_t row_index(size_t cell_index) {
        return cell_index/sp_columns;
    }
    static size_t column_index(size_t cell_index) {
        return cell_index % sp_columns;
    }

    std::array<int, sp_cells> cells_;
};

abelian_sandpile::abelian_sandpile() {
    cells_.fill(0);
}

abelian_sandpile::abelian_sandpile(std::initializer_list<int> init) {
    assert(init.size() == sp_cells);
    std::copy(init.begin(), init.end(), cells_.begin());
}

abelian_sandpile& abelian_sandpile::operator+=(const abelian_sandpile& other) {
    for (size_t i = 0; i < sp_cells; ++i)
        cells_[i] += other.cells_[i];
    stabilize();
    return *this;
}

bool abelian_sandpile::operator==(const abelian_sandpile& other) {
    return cells_ == other.cells_;
}

bool abelian_sandpile::is_stable() const {
    return std::none_of(cells_.begin(), cells_.end(),
                        [](int a) { return a >= sp_limit; });
}

void abelian_sandpile::topple() {
    for (size_t i = 0; i < sp_cells; ++i) {
        if (cells_[i] >= sp_limit) {
            cells_[i] -= sp_limit;
            size_t row = row_index(i);
            size_t column = column_index(i);
            if (row > 0)
                ++cell_value(row - 1, column);
            if (row + 1 < sp_rows)
                ++cell_value(row + 1, column);
            if (column > 0)
                ++cell_value(row, column - 1);
            if (column + 1 < sp_columns)
                ++cell_value(row, column + 1);
            break;
        }
    }
}

void abelian_sandpile::stabilize() {
    while (!is_stable())
        topple();
}

abelian_sandpile operator+(const abelian_sandpile& a, const abelian_sandpile& b) {
    abelian_sandpile c(a);
    c += b;
    return c;
}

std::ostream& operator<<(std::ostream& out, const abelian_sandpile& as) {
    for (size_t i = 0; i < sp_cells; ++i) {
        if (i > 0)
            out << (as.column_index(i) == 0 ? '\n' : ' ');
        out << as.cells_[i];
    }
    return out << '\n';
}

int main() {
    std::cout << std::boolalpha;

    std::cout << "Avalanche:\n";
    abelian_sandpile sp{4,3,3, 3,1,2, 0,2,3};
    while (!sp.is_stable()) {
        std::cout << sp << "stable? " << sp.is_stable() << "\n\n";
        sp.topple();
    }
    std::cout << sp << "stable? " << sp.is_stable() << "\n\n";

    std::cout << "Commutativity:\n";
    abelian_sandpile s1{1,2,0, 2,1,1, 0,1,3};
    abelian_sandpile s2{2,1,3, 1,0,1, 0,1,0};
    abelian_sandpile sum1(s1 + s2);
    abelian_sandpile sum2(s2 + s1);
    std::cout << "s1 + s2 equals s2 + s1? " << (sum1 == sum2) << "\n\n";
    std::cout << "s1 + s2 = \n" << sum1;
    std::cout << "\ns2 + s1 = \n" << sum2;
    std::cout << '\n';

    std::cout << "Identity:\n";
    abelian_sandpile s3{3,3,3, 3,3,3, 3,3,3};
    abelian_sandpile s3_id{2,1,2, 1,0,1, 2,1,2};
    abelian_sandpile sum3(s3 + s3_id);
    abelian_sandpile sum4(s3_id + s3_id);
    std::cout << "s3 + s3_id equals s3? " << (sum3 == s3) << '\n';
    std::cout << "s3_id + s3_id equals s3_id? " << (sum4 == s3_id) << "\n\n";
    std::cout << "s3 + s3_id = \n" << sum3;
    std::cout << "\ns3_id + s3_id = \n" << sum4;

    return 0;
}


; file:   abstract.lsp
; url:    http://rosettacode.org/wiki/Abstract_type
; author: oofoe 2012-01-28

; Abstract Shape Class

(new Class 'Shape)     ; Derive new class.

(define (Shape:Shape   ; Shape constructor.
         (pen "X"))    ; Default value.
  (list (context)      ; Assemble data packet.
        (list 'pen pen)
        (list 'size (args))))

(define (Shape:line x) ; Print out row with 'pen' character.
  (dotimes (i x)
    (print (lookup 'pen (self))))
  (println))

(define (Shape:draw))  ; Placeholder, does nothing.

; Derived Objects

(new Shape 'Box)

(define (Box:draw)     ; Override base draw method.
  (let ((s (lookup 'size (self))))
    (dotimes (i (s 0)) (:line (self) (s 0)))))

(new Shape 'Rectangle)

(define (Rectangle:draw)
  (let ((size (lookup 'size (self))))
    (dotimes (i (size 1)) (:line (self) (size 0)))))

; Demonstration

(:draw (Shape))        ; Nothing happens.

(println "A box:")
(:draw (Box "O" 5))    ; Create Box object and call draw method.

(println "\nA rectangle:")
(:draw (Rectangle "R" 32 4))

(exit)


text:(
  "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." )

ta:{[aln;txt]                                                  / tabulate aligned
  sl:(count'')s:"$"vs/:txt;                                    /   strings and their lengths
  cw:{rl#\:max x@/:\:til max rl:count each x}sl;               /   cell widths
  ps:$[aln=`R;-1-cw;1+cw]$''s;                                 /   padded strings
  ps:$[aln=`C;(neg(cw-sl)div 2)rotate''ps;ps];                 /   center
  1,[;"\n\n"]"\n"sv raze each ps; }                            /   print


type
  Comparable = concept x, y
    (x < y) is bool

  Stack[T] = concept s, var v
    s.pop() is T
    v.push(T)

    s.len is Ordinal

    for value in s:
      value is T


# Task: abstract type
#
# Methods without implementation are annotated `abstract`.
#
# Abstract classes and interfaces can contain abstract methods and concrete (i.e. non-abstract) methods.
# Abstract classes can also have attributes.
module abstract_type

interface Inter
	fun method1: Int is abstract
	fun method2: Int do return 1
end

abstract class Abs
	fun method1: Int is abstract
	fun method2: Int do return 1
	var attr: Int
end


TYPE
  Animal = POINTER TO AnimalDesc;
  AnimalDec = RECORD [ABSTRACT] END;

  (* Cat inherits from Animal *)
  Cat = POINTER TO CatDesc;
  CatDesc = RECORD (AnimalDesc) END;


class ClassA {
   method : virtual : public : MethodA() ~ Int;

   method : public : MethodA() ~ Int {
      return 0;
   }
}


# Read in text
lines <- readLines(tc <- textConnection("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.")); close(tc)

#Split words by the dollar
words <- strsplit(lines, "\\$")

#Reformat
maxlen <- max(sapply(words, length))
words <- lapply(words, function(x) {length(x) <- maxlen; x})
block <- matrix(unlist(words), byrow=TRUE, ncol=maxlen)
block[is.na(block)] <- ""
leftjust <- format(block)
rightjust <- format(block, justify="right")
centrejust <- format(block, justify="centre")

# Print
print0 <- function(x) invisible(apply(x, 1, function(x) cat(x, "\n")))
print0(leftjust)
print0(rightjust)
print0(centrejust)


#lang racket

(define (display-aligned text #:justify [justify 'left])
  (define lines
    (for/list ([line (regexp-split #rx"\n" text)])
      (regexp-split #rx"\\$" line)))
  (define width
    (add1 (for*/fold ([m 0]) ([line lines] [word line])
            (max m (string-length word)))))
  (define spaces (make-string width #\space))
  (for ([line lines])
    (for* ([word line]
           [strs (let ([spc (substring spaces (string-length word))])
                   (case justify
                     [(left)  (list word spc)]
                     [(right) (list spc word)]
                     [(center) (let ([i (quotient (string-length spc) 2)])
                                 (list (substring spc i)
                                       word
                                       (substring spc 0 i)))]))])
      (display strs))
    (newline)))

(define text
  "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.")

(display-aligned text)
(display-aligned #:justify 'right text)
(display-aligned #:justify 'center text)


USING: arrays grouping io kernel math math.vectors prettyprint
qw sequences ;

CONSTANT: neighbors {
    { 1 3 } { 0 2 4 } { 1 5 } { 0 4 6 } { 1 3 5 7 }
    { 2 4 8 } { 3 7 } { 4 6 8 } { 5 7 }
}

! Sandpile words
: find-tall ( seq -- n ) [ 3 > ] find drop ;
: tall? ( seq -- ? ) find-tall >boolean ;
: distribute ( ind seq -- ) [ [ 1 + ] change-nth ] curry each ;
: adjacent ( n seq -- ) [ neighbors nth ] dip distribute ;
: shrink ( n seq -- ) [ 4 - ] change-nth ;
: (topple) ( n seq -- ) [ shrink ] [ adjacent ] 2bi ;
: topple ( seq -- seq' ) [ find-tall ] [ (topple) ] [ ] tri ;
: avalanche ( seq -- ) [ dup tall? ] [ topple ] while drop ;
: s+ ( seq1 seq2 -- seq3 ) v+ dup avalanche ;

! Output words
: mappend ( seq1 seq2 -- seq3 ) [ flip ] [email protected] append flip ;
: sym ( seq str -- seq ) 1array " " 1array tuck 3array mappend ;
: arrow ( seq -- new-seq ) ">" sym ;
: plus  ( seq -- new-seq ) "+" sym ;
: eq    ( seq -- new-seq ) "=" sym ;
: topple> ( seq seq -- seq seq ) arrow over topple 3 group mappend ;
: (.s+) ( seq seq seq -- seq ) [ plus ] [ mappend eq ] [ mappend ] tri* ;
: .s+ ( seq1 seq2 -- ) 2dup s+ [ 3 group ] [email protected] (.s+) simple-table. ;

! Task
CONSTANT: s1 { 1 2 0 2 1 1 0 1 3 }
CONSTANT: s2 { 2 1 3 1 0 1 0 1 0 }
CONSTANT: s3 { 3 3 3 3 3 3 3 3 3 }
CONSTANT: id { 2 1 2 1 0 1 2 1 2 }

"Avalanche:" print nl
{ 4 3 3 3 1 2 0 2 3 }
dup 3 group topple> topple> topple> topple> nip simple-table. nl

"s1 + s2 = s2 + s1" print nl
s1 s2 .s+ nl s2 s1 .s+ nl

"s3 + s3_id = s3" print nl
s3 id .s+ nl

"s3_id + s3_id = s3_id" print nl
id id .s+


package main

import (
    "fmt"
    "strconv"
    "strings"
)

type sandpile struct{ a [9]int }

var neighbors = [][]int{
    {1, 3}, {0, 2, 4}, {1, 5}, {0, 4, 6}, {1, 3, 5, 7}, {2, 4, 8}, {3, 7}, {4, 6, 8}, {5, 7},
}

// 'a' is in row order
func newSandpile(a [9]int) *sandpile { return &sandpile{a} }

func (s *sandpile) plus(other *sandpile) *sandpile {
    b := [9]int{}
    for i := 0; i < 9; i++ {
        b[i] = s.a[i] + other.a[i]
    }
    return &sandpile{b}
}

func (s *sandpile) isStable() bool {
    for _, e := range s.a {
        if e > 3 {
            return false
        }
    }
    return true
}

// just topples once so we can observe intermediate results
func (s *sandpile) topple() {
    for i := 0; i < 9; i++ {
        if s.a[i] > 3 {
            s.a[i] -= 4
            for _, j := range neighbors[i] {
                s.a[j]++
            }
            return
        }
    }
}

func (s *sandpile) String() string {
    var sb strings.Builder
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            sb.WriteString(strconv.Itoa(s.a[3*i+j]) + " ")
        }
        sb.WriteString("\n")
    }
    return sb.String()
}

func main() {
    fmt.Println("Avalanche of topplings:\n")
    s4 := newSandpile([9]int{4, 3, 3, 3, 1, 2, 0, 2, 3})
    fmt.Println(s4)
    for !s4.isStable() {
        s4.topple()
        fmt.Println(s4)
    }

    fmt.Println("Commutative additions:\n")
    s1 := newSandpile([9]int{1, 2, 0, 2, 1, 1, 0, 1, 3})
    s2 := newSandpile([9]int{2, 1, 3, 1, 0, 1, 0, 1, 0})
    s3_a := s1.plus(s2)
    for !s3_a.isStable() {
        s3_a.topple()
    }
    s3_b := s2.plus(s1)
    for !s3_b.isStable() {
        s3_b.topple()
    }
    fmt.Printf("%s\nplus\n\n%s\nequals\n\n%s\n", s1, s2, s3_a)
    fmt.Printf("and\n\n%s\nplus\n\n%s\nalso equals\n\n%s\n", s2, s1, s3_b)

    fmt.Println("Addition of identity sandpile:\n")
    s3 := newSandpile([9]int{3, 3, 3, 3, 3, 3, 3, 3, 3})
    s3_id := newSandpile([9]int{2, 1, 2, 1, 0, 1, 2, 1, 2})
    s4 = s3.plus(s3_id)
    for !s4.isStable() {
        s4.topple()
    }
    fmt.Printf("%s\nplus\n\n%s\nequals\n\n%s\n", s3, s3_id, s4)

    fmt.Println("Addition of identities:\n")
    s5 := s3_id.plus(s3_id)
    for !s5.isStable() {
        s5.topple()
    }
    fmt.Printf("%s\nplus\n\n%s\nequals\n\n%s", s3_id, s3_id, s5)
}


class virtual foo =
  object
    method virtual bar : int
  end


Property new: Spherical(r)
Spherical method: radius  @r ;
Spherical method: setRadius  := r ;
Spherical method: perimeter  @r 2 * PI * ;
Spherical method: surface   @r sq PI * 4 * ;

Object Class new: Ballon(color)
Ballon is: Spherical
Ballon method: initialize(color, r)  color := color self setRadius(r) ;

Object Class new: Planete(name)
Planete is: Spherical
Planete method: initialize(n, r)  n := name self setRadius(r) ;


  -- Example showing a class that defines an interface in ooRexx
  -- shape is the interface class that defines the methods a shape instance
  -- is expected to implement as abstract methods.  Instances of the shape
  -- class need not directly subclass the interface, but can use multiple
  -- inheritance to mark itself as implementing the interface.

  r=.rectangle~new(5,2)
  say r
  -- check for instance of
  if r~isa(.shape) then say "a" r~name "is a shape"
  say "r~area:" r~area
  say

  c=.circle~new(2)
  say c
  -- check for instance of shape works even if inherited
  if c~isa(.shape) then say "a" c~name "is a shape"
  say "c~area:" c~area
  say

  -- a mixin is still a class and can be instantiated.  The abstract methods
  -- will give an error if invoked
  g=.shape~new
  say g
  say g~name
  say "g~area:" g~area -- invoking abstract method results in a runtime error.

  -- the "MIXINCLASS" tag makes this avaiable for multiple inhertance
  ::class shape MIXINCLASS Object
    ::method area abstract
    ::method name abstract

  -- directly subclassing the the interface
  ::class rectangle subclass shape

    ::method init
      expose length width
      use strict arg length=0, width=0

    ::method area
      expose length width
      return length*width

    ::method name
      return "Rectangle"

  -- inherits the shape methods
  ::class circle subclass object inherit shape

    ::method init
      expose radius
      use strict arg radius=0

    ::method area
      expose radius
      numeric digits 20
      return radius*radius*3.14159265358979323846

    ::method name
      return "Circle"


my @lines =
q|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.
|.lines;

my @widths;

for @lines { for .split('$').kv { @widths[$^key] max= $^word.chars; } }
for @lines { say |.split('$').kv.map: { (align @widths[$^key], $^word) ~ " "; } }

sub align($column_width, $word, $aligment = @*ARGS[0]) {
        my $lr = $column_width - $word.chars;
        my $c  = $lr / 2;
        given ($aligment) {
                when "center" { " " x $c.ceiling ~ $word ~ " " x $c.floor }
                when "right"  { " " x $lr        ~ $word                  }
                default       {                    $word ~ " " x $lr      }
        }
}


{-# LANGUAGE TupleSections #-}

import Data.List (findIndex, transpose)
import Data.List.Split (chunksOf)

--------------------------- TEST ---------------------------
main :: IO ()
main = do
  let s0 = [[4, 3, 3], [3, 1, 2], [0, 2, 3]]
      s1 = [[1, 2, 0], [2, 1, 1], [0, 1, 3]]
      s2 = [[2, 1, 3], [1, 0, 1], [0, 1, 0]]
      s3_id = [[2, 1, 2], [1, 0, 1], [2, 1, 2]]
      s3 = replicate 3 (replicate 3 3)
      x:xs = reverse $ cascade s0
  mapM_
    putStrLn
    [ "Cascade:"
    , showCascade $ ([], x) : fmap ("->", ) xs

    , "s1 + s2 == s2 + s1 -> " <> show (addSand s1 s2 == addSand s2 s1)
    , showCascade [([], s1), (" +", s2), (" =", addSand s1 s2)]
    , showCascade [([], s2), (" +", s1), (" =", addSand s2 s1)]

    , "s3 + s3_id == s3 -> " <> show (addSand s3 s3_id == s3)
    , showCascade [([], s3), (" +", s3_id), (" =", addSand s3 s3_id)]

    , "s3_id + s3_id == s3_id -> " <> show (addSand s3_id s3_id == s3_id)
    , showCascade [([], s3_id), (" +", s3_id), (" =", addSand s3_id s3_id)]
    ]

------------------------ SAND PILES ------------------------
addSand :: [[Int]] -> [[Int]] -> [[Int]]
addSand xs ys =
  (head . cascade . chunksOf (length xs)) $ zipWith (+) (concat xs) (concat ys)

cascade :: [[Int]] -> [[[Int]]]
cascade xs = chunksOf w <$> convergence (==) (iterate (tumble w) (concat xs))
  where
    w = length xs

convergence :: (a -> a -> Bool) -> [a] -> [a]
convergence p = go
  where
    go (x:ys@(y:_))
      | p x y = [x]
      | otherwise = go ys <> [x]

tumble :: Int -> [Int] -> [Int]
tumble w xs = maybe xs go $ findIndex (w <) xs
  where
    go i = zipWith f [0 ..] xs
      where
        neighbours = indexNeighbours w i
        f j x
          | j `elem` neighbours = succ x
          | i == j = x - succ w
          | otherwise = x

indexNeighbours :: Int -> Int -> [Int]
indexNeighbours w = go
  where
    go i =
      concat
        [ [ j
          | j <- [i - w, i + w]
          , -1 < j
          , wSqr > j ]
        , [ pred i
          | 0 /= col ]
        , [ succ i
          | pred w /= col ]
        ]
      where
        wSqr = w * w
        col = rem i w

------------------------- DISPLAY --------------------------
showCascade :: [(String, [[Int]])] -> String
showCascade pairs =
  unlines $
  fmap unwords $
  transpose $
  fmap
    (\(pfx, xs) ->
        unwords <$> transpose (centered pfx : transpose (fmap (fmap show) xs)))
    pairs

centered :: String -> [String]
centered s = [pad, s, pad <> replicate r ' ']
  where
    lng = length s
    pad = replicate lng ' '
    (q, r) = quotRem (2 + lng) 2


'ABSTRACT TYPES EXAMPLE
'PARTICLES

type position {}
type angle    {}
type velocity {}
type mass     {}
type counter  {}

type particle
  position p
  angle    a
  velocity v
  mass     m
end type

class particles
  particle*q
  counter c
  method constructor (){}
  method destructor  (){}
  method action      (){}
end class


declare
  class BaseQueue
     attr
        contents:nil

     meth init
        raise notImplemented(self init) end
     end

     meth enqueue(Item)
        raise notImplemented(self enqueue) end
     end

     meth dequeue(?Item)
        raise notImplemented(self dequeue) end
     end

     meth printContents
        {ForAll @contents Show}
     end
  end

  Queue = {New BaseQueue init} %% throws


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

DefStr TextLeft, TextRight, TextCenter
DefStr MLine, LWord, Newline = chr$(13)+chr$(10)
DefInt ColWidth(100), ColCount
DefSng NrSpaces

'Find column widths
MText.position = 0
for x = 0 to MText.linecount -1
    MLine = MText.ReadLine
    for y = 0 to Tally(MLine, "$")
        LWord = Field$(MLine, "$", y+1)
        ColWidth(y) = iif (ColWidth(y) < len(LWord), len(LWord), ColWidth(y))
    next
next

'Create aligned wordlists
MText.position = 0
for x = 0 to MText.linecount -1
    MLine = MText.ReadLine
    for y = 0 to Tally(MLine, "$")
        LWord = Field$(MLine, "$", y+1)
        NrSpaces = ColWidth(y) - len(LWord)
        'left align
        TextLeft = TextLeft + LWord + Space$(NrSpaces+1)
        'Right align
        TextRight = TextRight + Space$(NrSpaces+1) + LWord
        'Center
        TextCenter = TextCenter + Space$(floor((NrSpaces)/2)+1) + LWord + Space$(Ceil((NrSpaces)/2))
    next
    TextLeft = TextLeft + Newline
    TextRight = TextRight + Newline
    TextCenter = TextCenter + Newline
next


rebol [
	Title: "Align Columns"
	URL: http://rosettacode.org/wiki/Align_columns
]

specimen: {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.}

; Parse specimen into data grid.

data: copy []
foreach line parse specimen to-string lf [ ; Break into lines.
	append/only data parse line "$"        ; Break into columns.
]

; Compute independent widths for each column.

widths: copy []  insert/dup widths 0 length? data/1
foreach line data [
	forall line [
		i: index? line
		widths/:i: max widths/:i length? line/1
	]
]

pad: func [n /local x][x: copy ""  insert/dup x " " n  x]

; These formatting functions are passed as arguments to entable.

right: func [n s][rejoin [pad n - length? s  s]]

left: func [n s][rejoin [s  pad n - length? s]]

centre: func [n s /local h][
	h: round/down (n - length? s) / 2
	rejoin [pad h  s  pad n - h - length? s]
]

; Display data as table.

entable: func [data format] [
	foreach line data [
		forall line [
			prin rejoin [format  pick widths index? line  line/1  " "]
		]
		print ""
	]
]

; Format data table.

foreach i [left centre right] [
	print ["^/Align" i "...^/"]  entable data get i]


import Base.+, Base.print

struct Sandpile
    pile::Matrix{UInt8}
end

function Sandpile(s::String)
    arr = [parse(UInt8, x.match) for x in eachmatch(r"\d+", s)]
    siz = isqrt(length(arr))
    return Sandpile(reshape(UInt8.(arr), siz, siz)')
end

const HMAX = 3

function avalanche!(s::Sandpile, lim=HMAX)
    nrows, ncols = size(s.pile)
    while any(x -> x > lim, s.pile)
        for j in 1:ncols, i in 1:nrows
            if s.pile[i, j] > lim
                i > 1 && (s.pile[i - 1, j] += 1)
                i < nrows && (s.pile[i + 1, j] += 1)
                j > 1 && (s.pile[i, j - 1] += 1)
                j < ncols && (s.pile[i, j + 1] += 1)
                s.pile[i, j] -= 4
            end
        end
    end
    s
end

+(s1::Sandpile, s2::Sandpile) = avalanche!(Sandpile((s1.pile + s2.pile)))

function print(io::IO, s::Sandpile)
    for row in 1:size(s.pile)[1]
        for col in 1:size(s.pile)[2]
            print(io, lpad(s.pile[row, col], 4))
        end
        println()
    end
end

const s1 = Sandpile("""
    1 2 0
    2 1 1
    0 1 3""")

const s2 = Sandpile("""
    2 1 3
    1 0 1
    0 1 0""")

const s3 = Sandpile("""
    3 3 3
    3 3 3
    3 3 3""")

const s3_id = Sandpile("""
    2 1 2
    1 0 1
    2 1 2""")

const s3a = Sandpile("""
    4 3 3
    3 1 2
    0 2 3""")

println("Avalanche reduction to group:\n", s3a, "   =>")
println(avalanche!(s3a), "\n")

println("Commutative Property:\ns1 + s2 =\n", s1 + s2, "\ns2 + s1 =\n", s2 + s1, "\n")

println("Addition:\n", s3, "   +\n", s3_id, "   =\n", s3 + s3_id, "\n")
println(s3_id, "   +\n", s3_id, "   =\n", s3_id + s3_id, "\n")


sandpile.__index = sandpile
sandpile.new = function(self, vals)
  local inst = setmetatable({},sandpile)
  inst.cell, inst.dim = {}, #vals
  for r = 1, inst.dim do
    inst.cell[r] = {}
    for c = 1, inst.dim do
      inst.cell[r][c] = vals[r][c]
    end
  end
  return inst
end
sandpile.add = function(self, other)
  local vals = {}
  for r = 1, self.dim do
    vals[r] = {}
    for c = 1, self.dim do
      vals[r][c] = self.cell[r][c] + other.cell[r][c]
    end
  end
  local inst = sandpile:new(vals)
  inst:iter()
  return inst
end

local s1 = sandpile:new{{1,2,0},{2,1,1},{0,1,3}}
local s2 = sandpile:new{{2,1,3},{1,0,1},{0,1,0}}
print("s1 =")  s1:draw()
print("\ns2 =")  s2:draw()
local s1ps2 = s1:add(s2)
print("\ns1 + s2 =")  s1ps2:draw()
local s2ps1 = s2:add(s1)
print("\ns2 + s1 =")  s2ps1:draw()
local topple = sandpile:new{{4,3,3},{3,1,2},{0,2,3}}
print("\ntopple, before =")  topple:draw()
topple:iter()
print("\ntopple, after =")  topple:draw()
local s3 = sandpile:new{{3,3,3},{3,3,3},{3,3,3}}
print("\ns3 =")  s3:draw()
local s3_id = sandpile:new{{2,1,2},{1,0,1},{2,1,2}}
print("\ns3_id =") s3_id:draw()
local s3ps3_id = s3:add(s3_id)
print("\ns3 + s3_id =")  s3ps3_id:draw()
local s3_idps3_id = s3_id:add(s3_id)
print("\ns3_id + s3_id =")  s3_idps3_id:draw()


package AbstractFoo;

use strict;

sub frob { die "abstract" }
sub baz { die "abstract" }

sub frob_the_baz {
    my $self = shift;
    $self->frob($self->baz());
}

1;


Red [
  Title: "Align Columns"
  Original-Author: oofoe
]

text: {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.}

; Parse specimen into data grid.

data: copy []
foreach line split text lf [
  append/only data split line "$"
]

; Compute independent widths for each column.

widths: copy []
foreach line data [
  forall line [
    i: index? line
    if i > length? widths [append widths 0]
    widths/:i: max widths/:i length? line/1
  ]
]

pad: function [n] [x: copy "" insert/dup x " " n x]

; These formatting functions are passed as arguments to entable.

right: func [n s][rejoin [pad n - length? s s]]

left: func [n s][rejoin [s pad n - length? s]]

centre: function [n s] [
  d: n - length? s
  h: round/down d / 2
  rejoin [pad h s pad d - h]
]

; Display data as table.

entable: func [data format] [
  foreach line data [
    forall line [
      prin rejoin [format pick widths index? line line/1 " "]
    ]
    print ""
  ]
]

; Format data table.

foreach i [left centre right] [
  print [newline "Align" i "..." newline]  entable data get i]


/*REXX*/
z.1 = "Given$a$text$file$of$many$lines,$where$fields$within$a$line$"
z.2 = "are$delineated$by$a$single$'dollar'$character,$write$a$program"
z.3 = "that$aligns$each$column$of$fields$by$ensuring$that$words$in$each$"
z.4 = "column$are$separated$by$at$least$one$space."
z.5 = "Further,$allow$for$each$word$in$a$column$to$be$either$left$"
z.6 = "justified,$right$justified,$or$center$justified$within$its$column."

word. = ""
width. = 0
maxcol = 0
do row = 1 to 6
  line = z.row
  do col = 1 by 1 until length(line) = 0
    parse var line word.row.col "$" line
    if length(word.row.col) > width.col then width.col = length(word.row.col)
  end
  if col > maxcol then maxcol = col
end

say "align left:"
say
do row = 1 to 6
  out = ""
  do col = 1 to maxcol
    out = out || left(word.row.col,width.col+1)
  end
  say out
end
say
say "align right:"
say
do row = 1 to 6
  out = ""
  do col = 1 to maxcol
    out = out || right(word.row.col,width.col+1)
  end
  say out
end
say
say "align center:"
say
do row = 1 to 6
  out = ""
  do col = 1 to maxcol
    out = out || center(word.row.col,width.col+1)
  end
  say out
end


(* https://en.wikipedia.org/wiki/Abelian_sandpile_model *)

module Make =
  functor (M : sig val m : int val n : int end)
  -> struct

    type t = { grid : int array array ; unstable : ((int*int),unit) Hashtbl.t }

    let make () = { grid = Array.init M.m (fun _ -> Array.make M.n 0); unstable = Hashtbl.create 10 }

    let print {grid=grid} =
      for i = 0 to M.m - 1
      do for j = 0 to M.n - 1
         do Printf.printf "%d " grid.(i).(j)
         done
       ; print_newline ()
       done

    let add_grain {grid=grid;unstable=unstable} x y
      = grid.(x).(y) <- grid.(x).(y) + 1
      ; if grid.(x).(y) >= 4 then
          Hashtbl.replace unstable (x,y) () (* Use Hashtbl.replace for uniqueness *)

    let topple ({grid=grid;unstable=unstable} as s) x y
      = grid.(x).(y) <- grid.(x).(y) - 4
      ; if grid.(x).(y) < 4
        then Hashtbl.remove unstable (x,y)
      ; let add_grain = add_grain s in match (x,y) with
        (* corners *)
        | (0,0) -> add_grain 1 0
                 ; add_grain 0 1
        | (0,n) when n = M.n - 1
          -> add_grain 1 n
           ; add_grain 0 (n-1)
        | (m,0) when m = M.m - 1
          -> add_grain m 1
           ; add_grain (m-1) 0
        | (m,n) when m = M.m - 1 && n = M.n - 1
          -> add_grain ( m ) (n-1)
           ; add_grain (m-1) ( n )
        (* sides *)
        | (0,y) -> add_grain 1 y
                 ; add_grain 0 (y+1)
                 ; add_grain 0 (y-1)
        | (m,y) when m = M.m - 1
          -> add_grain ( m ) (y-1)
           ; add_grain ( m ) (y+1)
           ; add_grain (m-1) ( y )
        | (x,0) -> add_grain (x+1) 0
                 ; add_grain (x-1) 0
                 ; add_grain ( x ) 1
        | (x,n) when n = M.n - 1
          -> add_grain (x-1) ( n )
           ; add_grain (x+1) ( n )
           ; add_grain ( x ) (n-1)
        (* else *)
        | (x,y) -> add_grain ( x ) (y+1)
                 ; add_grain ( x ) (y-1)
                 ; add_grain (x+1) ( y )
                 ; add_grain (x-1) ( y )

    let add_sand s n x y
      = for i = 1 to n
        do add_grain s x y
        done

    let avalanche ?(avalanche_print=fun _ -> ()) ({grid=grid;unstable=unstable} as s)
      = while Hashtbl.length unstable > 0
        do
         let unstable' = Hashtbl.fold  (fun (x,y) () r -> (x,y) :: r) unstable []
         in List.iter (fun (x,y) -> topple s x y; avalanche_print s ) unstable'
        done

    let init ?(avalanche_print=fun _ -> ()) f
      = let s = { grid = Array.init M.m (fun x -> Array.init M.n (fun y -> f x y)) ; unstable = Hashtbl.create 10 }
        in Array.iteri (fun x -> Array.iteri (fun y e -> if e >= 4 then Hashtbl.replace s.unstable (x,y) ())) s.grid
         ; avalanche_print s
         ; avalanche ~avalanche_print s
         ; s

    let sandpile n
      = let s = make ()
        in add_sand s n (M.m/2) (M.n/2)
         ; avalanche s
         ; s

    let (+.) {grid=a} {grid=b}
      = let c = init (fun x y -> a.(x).(y) + b.(x).(y))
        in avalanche c
         ; c
  end

(* testing *)

let ()
  = let module S = Make (struct let m = 3 let n = 3 end)
    in let open S
       in print_endline "Avalanche example"
        ; begin
           let s0 = init ~avalanche_print:(fun s -> print s
                                                  ; print_endline "  ↓")
                      (fun x y -> [| [| 4 ; 3 ; 3 |]
                                   ; [| 3 ; 1 ; 2 |]
                                   ; [| 0 ; 2 ; 3 |]
                                  |].(x).(y))
           in print s0
            ; print_endline "---------------"
         end
        ; print_endline "Addition example"
        ; begin
            let  s1 = init (fun x y -> [| [| 1 ; 2 ; 0 |]
                                        ; [| 2 ; 1 ; 1 |]
                                        ; [| 0 ; 1 ; 3 |]
                                       |].(x).(y))
             and s2 = init (fun x y -> [| [| 2 ; 1 ; 3 |]
                                        ; [| 1 ; 0 ; 1 |]
                                        ; [| 0 ; 1 ; 0|]
                                       |].(x).(y))
             and s3 = init (fun _ _ -> 3)
             and s3_id = init (fun x y -> match (x,y) with
                                          | ((0,0)|(2,0)|(0,2)|(2,2)) -> 2
                                          | ((1,0)|(1,2)|(0,1)|(2,1)) -> 1
                                          | _ -> 0)
            in print s1
             ; print_endline "  +"
             ; print s2
             ; print_endline "  ="
             ; print (s1 +. s2)
             ; print_endline "------ Identity examples -----"
             ; print s3
             ; print_endline "  +"
             ; print s3_id
             ; print_endline "  ="
             ; print (s3 +. s3_id)
             ; print_endline "-----"
             ; print s3_id
             ; print_endline "  +"
             ; print s3_id
             ; print_endline "  ="
             ; print (s3_id +. s3_id)
          end


abstract class job
    integer id
--  procedure test(); -- (the ; makes it an abstract method)
    procedure show()
        printf(1,"this is job:%d\n",id)
    end procedure
end class
--job j = new({1})  -- compilation error: "abstract class"

class errand extends job
end class
errand e = new({2})
e.show()


abstract class Abs {
	abstract public function method1($value);
	abstract protected function method2($name);
	function add($a, $b){
		return a + b;
	}
}


# In PicoLisp there is no formal difference between abstract and concrete classes.
# There is just a naming convention where abstract classes start with a
# lower-case character after the '+' (the naming convention for classes).
# This tells the programmer that this class has not enough methods
# defined to survive on its own.

(class +abstractClass)

(dm someMethod> ()
   (foo)
   (bar) )


J2justifier = {Left: :ljust, Right: :rjust, Center: :center}

=begin
Justify columns of textual tabular input where the record separator is the newline
and the field separator is a 'dollar' character.
justification can be Symbol; (:Left, :Right, or :Center).

Return the justified output as a string
=end
def aligner(infile, justification = :Left)
  fieldsbyrow = infile.map {|line| line.strip.split('$')}
  # pad to same number of fields per record
  maxfields = fieldsbyrow.map(&:length).max
  fieldsbyrow.map! {|row| row + ['']*(maxfields - row.length)}
  # calculate max fieldwidth per column
  colwidths = fieldsbyrow.transpose.map {|column|
    column.map(&:length).max
  }
  # pad fields in columns to colwidth with spaces
  justifier = J2justifier[justification]
  fieldsbyrow.map {|row|
    row.zip(colwidths).map {|field, width|
      field.send(justifier, width)
    }.join(" ")
  }.join("\n")
end

require 'stringio'

textinfile = <<END
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.
END

for align in [:Left, :Right, :Center]
  infile = StringIO.new(textinfile)
  puts "\n# %s Column-aligned output:" % align
  puts aligner(infile, align)
end


constant s1 = {"1 2 0",
               "2 1 1",
               "0 1 3"},

         s2 = {"2 1 3",
               "1 0 1",
               "0 1 0"},

         s3 = {"3 3 3",
               "3 3 3",
               "3 3 3"},

      s3_id = {"2 1 2",
               "1 0 1",
               "2 1 2"},

         s4 = {"4 3 3",
               "3 1 2",
               "0 2 3"}

function add(sequence s, t)
    for i=1 to 3 do
        for j=1 to 5 by 2 do
            s[i][j] += t[i][j]-'0'
        end for
    end for
    return s
end function

function topple(sequence s, integer one=0)
    for i=1 to 3 do
        for j=1 to 5 by 2 do
            if s[i][j]>'3' then
                s[i][j] -= 4
                if i>1 then s[i-1][j] += 1 end if
                if i<3 then s[i+1][j] += 1 end if
                if j>1 then s[i][j-2] += 1 end if
                if j<5 then s[i][j+2] += 1 end if
                if one=1 then return s end if
                one = -1
            end if
        end for
    end for
    return iff(one=1?{}:iff(one=-1?topple(s):s))
end function

procedure shout(sequence s)
    sequence r = repeat("",5)
    for i=1 to length(s) do
        sequence si = s[i]
        if string(si) then
            string ti = repeat(' ',length(si))
            r[1] &= ti
            r[2] &= si
            r[3] &= ti
        else
            for j=1 to 3 do
                r[j] &= si[j]
            end for
        end if
    end for
    puts(1,join(r,"\n"))
end procedure

puts(1,"1. Show avalanche\n\n")
sequence s = s4,
         res = {"    ",s}
while true do
    s = topple(s,1)
    if s={} then exit end if
    res &= {" ==> ",s}
end while
shout(res)

puts(1,"2. Prove s1 + s2 = s2 + s1\n\n")
shout({"    ",s1,"  +  ",s2,"  =  ",topple(add(s1,s2))})
shout({"    ",s2,"  +  ",s1,"  =  ",topple(add(s2,s1))})

puts(1,"3. Show that s3 + s3_id == s3\n\n")
shout({"    ",s3,"  +  ",s3_id,"  =  ",topple(add(s3,s3_id))})

puts(1,"4. Show that s3_id + s3_id == s3_id\n\n")
shout({"    ",s3_id,"  +  ",s3_id,"  =  ",topple(add(s3_id,s3_id))})


#Requires -Version 5.0

Class Player
{
  <#
    Properties: Name, Team, Position and Number
  #>
    [string]$Name

    [ValidateSet("Baltimore Ravens","Cincinnati Bengals","Cleveland Browns","Pittsburgh Steelers",
                 "Chicago Bears","Detroit Lions","Green Bay Packers","Minnesota Vikings",
                 "Houston Texans","Indianapolis Colts","Jacksonville Jaguars","Tennessee Titans",
                 "Atlanta Falcons","Carolina Panthers","New Orleans Saints","Tampa Bay Buccaneers",
                 "Buffalo Bills","Miami Dolphins","New England Patriots","New York Jets",
                 "Dallas Cowboys","New York Giants","Philadelphia Eagles","Washington Redskins",
                 "Denver Broncos","Kansas City Chiefs","Oakland Raiders","San Diego Chargers",
                 "Arizona Cardinals","Los Angeles Rams","San Francisco 49ers","Seattle Seahawks")]
    [string]$Team

    [ValidateSet("C","G","T","QB","RB","WR","TE","DT","DE","ILB","OLB","CB","S","K","H","LS","P","KOS","R")]
    [string]$Position

    [ValidateRange(0,99)]
    [int]$Number

  <#
    Constructor: Creates a new Player object, with the specified Name, Team, Position and Number.
  #>
    Player([string]$Name, [string]$Team, [string]$Position, [int]$Number)
    {
        $this.Name     = (Get-Culture).TextInfo.ToTitleCase("$Name")
        $this.Team     = (Get-Culture).TextInfo.ToTitleCase("$Team")
        $this.Position = $Position.ToUpper()
        $this.Number   = $Number
    }

  <#
    Methods: Trade the player to a different team (optional parameters for methods in PowerShell 5 classes are not available.  Boo!!)
             An overloaded method is a method with the same name as another method but in a different context,
             in this case with different parameters.
  #>
    Trade([string]$NewTeam)
    {
        [string[]]$league = "Baltimore Ravens","Cincinnati Bengals","Cleveland Browns","Pittsburgh Steelers",
                            "Chicago Bears","Detroit Lions","Green Bay Packers","Minnesota Vikings",
                            "Houston Texans","Indianapolis Colts","Jacksonville Jaguars","Tennessee Titans",
                            "Atlanta Falcons","Carolina Panthers","New Orleans Saints","Tampa Bay Buccaneers",
                            "Buffalo Bills","Miami Dolphins","New England Patriots","New York Jets",
                            "Dallas Cowboys","New York Giants","Philadelphia Eagles","Washington Redskins",
                            "Denver Broncos","Kansas City Chiefs","Oakland Raiders","San Diego Chargers",
                            "Arizona Cardinals","Los Angeles Rams","San Francisco 49ers","Seattle Seahawks"

        if ($NewTeam -in $league | Where-Object {$_ -notmatch $this.Team})
        {
            $this.Team = (Get-Culture).TextInfo.ToTitleCase("$NewTeam")
        }
        else
        {
            throw "Invalid Team"
        }
    }

    Trade([string]$NewTeam, [int]$NewNumber)
    {
        [string[]]$league = "Baltimore Ravens","Cincinnati Bengals","Cleveland Browns","Pittsburgh Steelers",
                            "Chicago Bears","Detroit Lions","Green Bay Packers","Minnesota Vikings",
                            "Houston Texans","Indianapolis Colts","Jacksonville Jaguars","Tennessee Titans",
                            "Atlanta Falcons","Carolina Panthers","New Orleans Saints","Tampa Bay Buccaneers",
                            "Buffalo Bills","Miami Dolphins","New England Patriots","New York Jets",
                            "Dallas Cowboys","New York Giants","Philadelphia Eagles","Washington Redskins",
                            "Denver Broncos","Kansas City Chiefs","Oakland Raiders","San Diego Chargers",
                            "Arizona Cardinals","Los Angeles Rams","San Francisco 49ers","Seattle Seahawks"

        if ($NewTeam -in $league | Where-Object {$_ -notmatch $this.Team})
        {
            $this.Team = (Get-Culture).TextInfo.ToTitleCase("$NewTeam")
        }
        else
        {
            throw "Invalid Team"
        }

        if ($NewNumber -in 0..99)
        {
            $this.Number = $NewNumber
        }
        else
        {
            throw "Invalid Number"
        }
    }
}


theString$ = "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."

x = shoTable(theString$,"left",6)
x = shoTable(theString$,"right",6)
x = shoTable(theString$,"center",6)
end

FUNCTION shoTable(theString$,align$,across)
print "------------ align:";align$;" -- across:";across;" ------------"
dim siz(across)
b$ = "                                          "
while word$(theString$,i+1,"$") <> ""
	siz(i mod across) = max(siz(i mod across),len(word$(theString$,i + 1,"$")))
	i = i + 1
wend
for i = 0 to across - 1
	siz(i) = siz(i) + 1
	if siz(i) and 1 then siz(i) = siz(i) + 1
next i

i = 0
a$ = word$(theString$,i+1,"$")
while a$ <> ""
        s = siz(i mod across) - len(a$)
	if align$ = "right"   then a$ = left$(b$,s);a$
	if align$ = "left"    then a$ = a$;left$(b$,s)
	if align$ = "center"  then a$ = left$(b$,int(s / 2));a$;left$(b$,int(s / 2) + (s and 1))
	print "|";a$;
	i  = i + 1
	if i mod across = 0 then print "|"
	a$ = word$(theString$,i+1,"$")
wend
print
end function


use std::iter::{repeat, Extend};

enum AlignmentType {
    Left,
    Center,
    Right,
}

fn get_column_widths(text: &str) -> Vec<usize> {
    let mut widths = Vec::new();
    for line in text
        .lines()
        .map(|s| s.trim_matches(' ').trim_end_matches('$'))
    {
        let lens = line.split('$').map(|s| s.chars().count());
        for (idx, len) in lens.enumerate() {
            if idx < widths.len() {
                widths[idx] = std::cmp::max(widths[idx], len);
            } else {
                widths.push(len);
            }
        }
    }
    widths
}

fn align_columns(text: &str, alignment: AlignmentType) -> String {
    let widths = get_column_widths(text);
    let mut result = String::new();
    for line in text
        .lines()
        .map(|s| s.trim_matches(' ').trim_end_matches('$'))
    {
        for (s, w) in line.split('$').zip(widths.iter()) {
            let blank_count = w - s.chars().count();
            let (pre, post) = match alignment {
                AlignmentType::Left => (0, blank_count),
                AlignmentType::Center => (blank_count / 2, (blank_count + 1) / 2),
                AlignmentType::Right => (blank_count, 0),
            };
            result.extend(repeat(' ').take(pre));
            result.push_str(s);
            result.extend(repeat(' ').take(post));
            result.push(' ');
        }
        result.push_str("\n");
    }
    result
}

fn main() {
    let text = r#"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."#;

    println!("{}", align_columns(text, AlignmentType::Left));
    println!("{}", repeat('-').take(110).collect::<String>());
    println!("{}", align_columns(text, AlignmentType::Center));
    println!("{}", repeat('-').take(110).collect::<String>());
    println!("{}", align_columns(text, AlignmentType::Right));
}


from itertools import product
from collections import defaultdict

class Sandpile():
    def __init__(self, gridtext):
        array = [int(x) for x in gridtext.strip().split()]
        self.grid = defaultdict(int,
                                {(i //3, i % 3): x
                                 for i, x in enumerate(array)})

    _border = set((r, c)
                  for r, c in product(range(-1, 4), repeat=2)
                  if not 0 <= r <= 2 or not 0 <= c <= 2
                  )
    _cell_coords = list(product(range(3), repeat=2))

    def topple(self):
        g = self.grid
        for r, c in self._cell_coords:
            if g[(r, c)] >= 4:
                g[(r - 1, c)] += 1
                g[(r + 1, c)] += 1
                g[(r, c - 1)] += 1
                g[(r, c + 1)] += 1
                g[(r, c)] -= 4
                return True
        return False

    def stabilise(self):
        while self.topple():
            pass
        # Remove extraneous grid border
        g = self.grid
        for row_col in self._border.intersection(g.keys()):
            del g[row_col]
        return self

    __pos__ = stabilise     # +s == s.stabilise()

    def __eq__(self, other):
        g = self.grid
        return all(g[row_col] == other.grid[row_col]
                   for row_col in self._cell_coords)

    def __add__(self, other):
        g = self.grid
        ans = Sandpile("")
        for row_col in self._cell_coords:
            ans.grid[row_col] = g[row_col] + other.grid[row_col]
        return ans.stabilise()

    def __str__(self):
        g, txt = self.grid, []
        for row in range(3):
            txt.append(' '.join(str(g[(row, col)])
                                for col in range(3)))
        return '\n'.join(txt)

    def __repr__(self):
        return f'{self.__class__.__name__}(""""\n{self.__str__()}""")'

unstable = Sandpile("""
4 3 3
3 1 2
0 2 3""")
s1 = Sandpile("""
    1 2 0
    2 1 1
    0 1 3
""")
s2 = Sandpile("""
    2 1 3
    1 0 1
    0 1 0
""")
s3 = Sandpile("3 3 3  3 3 3  3 3 3")
s3_id = Sandpile("2 1 2  1 0 1  2 1 2")


class BaseQueue(object):
    """Abstract/Virtual Class
    """
    def __init__(self):
        self.contents = list()
        raise NotImplementedError
    def Enqueue(self, item):
        raise NotImplementedError
    def Dequeue(self):
        raise NotImplementedError
    def Print_Contents(self):
        for i in self.contents:
            print i,


#lang racket

(define animal-interface (interface () say))

(define cat% (class* object% (animal-interface) (super-new))) ;; error

(define cat% (class* object% (animal-interface)
               (super-new)
               (define/public (say)
                 (display "meeeeew!"))))

(define tom (new cat%))
(send tom say)


use v6;

role A {
    # must be filled in by the class it is composed into
    method abstract() { ... };

    # can be overridden in the class, but that's not mandatory
    method concrete() { say '# 42' };
}

class SomeClass does A {
    method abstract() {
        say "# made concrete in class"
    }
}

my $obj = SomeClass.new;
$obj.abstract();
$obj.concrete();

# output:
# made concrete in class
# 42


object ColumnAligner {
  val eol = System.getProperty("line.separator")
  def getLines(filename: String) = scala.io.Source.fromPath(filename).getLines(eol)
  def splitter(line: String) = line split '$'
  def getTable(filename: String) = getLines(filename) map splitter
  def fieldWidths(fields: Array[String]) = fields map (_ length)
  def columnWidths(txt: Iterator[Array[String]]) = (txt map fieldWidths).toList.transpose map (_ max)

  def alignField(alignment: Char)(width: Int)(field: String) = alignment match {
    case 'l' | 'L' => "%-"+width+"s" format field
    case 'r' | 'R' => "%"+width+"s" format field
    case 'c' | 'C' => val padding = (width - field.length) / 2; " "*padding+"%-"+(width-padding)+"s" format field
    case _ => throw new IllegalArgumentException
  }

  def align(aligners: List[String => String])(fields: Array[String]) =
    aligners zip fields map Function.tupled(_ apply _)

  def alignFile(filename: String, alignment: Char) = {
    def table = getTable(filename)
    val aligners = columnWidths(table) map alignField(alignment)
    table map align(aligners) map (_ mkString " ")
  }

  def printAlignedFile(filename: String, alignment: Char) {
    alignFile(filename, alignment) foreach println
  }
}


class ASP {
    has $.h = 3;
    has $.w = 3;
    has @.pile = 0 xx $!w * $!h;

    method topple {
        my $buf = $!w * $!h;
        my $done;
        repeat {
            $done = True;
            loop (my int $row; $row < $!h; $row = $row + 1) {
                my int $rs = $row * $!w; # row start
                my int $re = $rs  + $!w; # row end
                loop (my int $idx = $rs; $idx < $re; $idx = $idx + 1) {
                    if self.pile[$idx] >= 4 {
                        my $grain = self.pile[$idx] div 4;
                        self.pile[ $idx - $!w ] += $grain if $row > 0;
                        self.pile[ $idx - 1  ]  += $grain if $idx - 1 >= $rs;
                        self.pile[ $idx + $!w ] += $grain if $row < $!h - 1;
                        self.pile[ $idx + 1  ]  += $grain if $idx + 1 < $re;
                        self.pile[ $idx ] %= 4;
                        $done = False;
                    }
                }
            }
        } until $done;
        self.pile;
    }
}

# some handy display layout modules
use Terminal::Boxer:ver<0.2+>;
use Text::Center;

for 3, (4,3,3,3,1,2,0,2,3), (2,1,2,1,0,1,2,1,2), # 3 square task example
    3, (2,1,2,1,0,1,2,1,2), (2,1,2,1,0,1,2,1,2), # 3 square identity
    5, (4,1,0,5,1,9,3,6,1,0,8,1,2,5,3,3,0,1,7,5,4,2,2,4,0), (2,3,2,3,2,3,2,1,2,3,2,1,0,1,2,3,2,1,2,3,2,3,2,3,2) # 5 square test
  -> $size, $pile, $identity {

    my $asp = ASP.new(:h($size), :w($size));

    $asp.pile = |$pile;

    my @display;

    my %p = :col($size), :3cw, :indent("\t");

    @display.push: rs-box |%p, |$identity;

    @display.push: rs-box |%p, $asp.pile;

    @display.push: rs-box |%p, $asp.topple;

    $asp.pile Z+= $identity.list;

    @display.push: rs-box |%p, $asp.pile;

    @display.push: rs-box |%p, $asp.topple;

    put %p<indent> ~ qww<identity 'test pile' toppled 'plus identity' toppled>».&center($size * 4 + 1).join: %p<indent>;

    .put for [Z~] @display».lines;

    put '';
}


rebol [
	Title: "Abstract Type"
	URL: http://rosettacode.org/wiki/Abstract_type
]

; The "shape" class is an abstract class -- it defines the "pen"
; property and "line" method, but "size" and "draw" are undefined and
; unimplemented.

shape: make object! [
	pen:  "X"
	size: none

	line: func [count][loop count [prin self/pen]  prin crlf]
	draw: does [none]
]

; The "box" class inherits from "shape" and provides the missing
; information for drawing boxes.

box: make shape [
	size: 10
	draw: does [loop self/size [line self/size]]
]

; "rectangle" also inherits from "shape", but handles the
; implementation very differently.

rectangle: make shape [
	size: 20x10
	draw: does [loop self/size/y [line self/size/x]]
]

; Unlike some languages discussed, REBOL has absolutely no qualms
; about instantiating an "abstract" class -- that's how I created the
; derived classes of "rectangle" and "box", after all.

s: make shape []  s/draw ; Nothing happens.

print "A box:"
b: make box [pen: "O" size: 5]  b/draw

print [crlf "A rectangle:"]
r: make rectangle [size: 32x5]  r/draw


Red [
  Title: "Abstract Type"
  Original-Author: oofoe
]

; The "shape" class is an abstract class -- it defines the "pen"
; property and "line" method, but "size" and "draw" are undefined and
; unimplemented.

shape: make object! [
  pen:  "X"
  size: none

  line: func [count][loop count [prin self/pen] prin newline]
  draw: does [none]
]

; The "box" class inherits from "shape" and provides the missing
; information for drawing boxes.

box: make shape [
  size: 10
  draw: does [loop self/size [line self/size]]
]

; "rectangle" also inherits from "shape", but handles the
; implementation very differently.

rectangle: make shape [
  size: 20x10
  draw: does [loop self/size/y [line self/size/x]]
]

; Unlike some languages discussed, REBOL has absolutely no qualms
; about instantiating an "abstract" class -- that's how I created the
; derived classes of "rectangle" and "box", after all.

print "An abstract shape (nothing):"
s: make shape []                s/draw ; Nothing happens.

print [newline "A box:"]
b: make box [pen: "O" size: 5]  b/draw

print [newline "A rectangle:"]
r: make rectangle [size: 32x5]  r/draw


require 'abstraction'

class AbstractQueue
  abstract
  def enqueue(object)
    raise NotImplementedError
  end
  def dequeue
    raise NotImplementedError
  end
end

class ConcreteQueue < AbstractQueue
  def enqueue(object)
    puts "enqueue #{object.inspect}"
  end
end


(import (scheme base)
        (scheme write)
        (srfi 1)
        (except (srfi 13) string-for-each string-map)
        (srfi 14))

;; text is a list of lines, alignment is left/right/center
;; displays the aligned text in columns with a single space gap
(define (align-columns text alignment)
  (define (split line) ; splits string on $ into list of strings
    (string-tokenize line (char-set-complement (->char-set "$"))))
  (define (extend lst n) ; extends list to length n, by adding "" to end
    (append lst (make-list (- n (length lst)) "")))
  (define (align-word word width) ; align single word to fit width
    (case alignment
      ((left) (string-pad-right word width))
      ((right) (string-pad word width))
      ((center) (let ((rem (- width (string-length word))))
                  (string-pad-right (string-pad word (- width (truncate (/ rem 2))))
                                    width)))))
  ;
  (display alignment) (newline)
  (let* ((text-list (map split text))
         (max-line-len (fold (lambda (text val) (max (length text) val)) 0 text-list))
         (text-lines (map (lambda (line) (extend line max-line-len)) text-list))
         (min-col-widths (map (lambda (col)
                                (fold (lambda (line val)
                                        (max (string-length (list-ref line col))
                                             val))
                                      0
                                      text-lines))
                              (iota max-line-len))))
    (map (lambda (line)
           (map (lambda (word width)
                  (display (string-append (align-word word width)
                                          " ")))
                line min-col-widths)
           (newline))
         text-lines))
  (newline))

;; show example
(define *example*
  '("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."))

(align-columns *example* 'left)
(align-columns *example* 'center)
(align-columns *example* 'right)


Red [Purpose: "implement Abelian sandpile model"]

sadd: make object! [
	comb: function [pile1 [series!] pile2 [series!]] [
		repeat r 3 [
			repeat c 3 [
				pile2/:r/:c: pile2/:r/:c + pile1/:r/:c
			]
		]
		check pile2
	]
	check: func [pile [series!]] [
		stable: true row: col: none
		repeat r 3[
			repeat c 3[
				if pile/:r/:c >= 4 [
					stable: false
					pile/:r/:c: pile/:r/:c - 4
					row: r col: c
					break]
			]
			if stable = false [break]
		]
		unless stable = false [print trim/with mold/only pile "[]" exit]
		spill pile row col
	]
	spill: func [pile [series!] r [integer!] c [integer!]] [
		neigh: reduce [
			right: reduce [r c - 1] up: reduce [r + 1 c]
			left: reduce [r c + 1] down: reduce [r - 1 c]
		]
		foreach n neigh [
			unless any [(pile/(n/1) = none) (pile/(n/1)/(n/2) = none)] [
				pile/(n/1)/(n/2): pile/(n/1)/(n/2) + 1
			]
		]
		check pile
	]
]

s1: [
	[1 2 0]
	[2 1 1]
	[0 1 3]
]

s2: [
	[2 1 3]
	[1 0 1]
	[0 1 0]
]

s3: [
	[3 3 3]
	[3 3 3]
	[3 3 3]
]

s3_id: [
	[2 1 2]
	[1 0 1]
	[2 1 2]
]

ex: [
	[4 3 3]
	[3 1 2]
	[0 2 3]
]

sadd/check copy/deep ex
sadd/comb copy/deep s1 copy/deep s2
sadd/comb copy/deep s2 copy/deep s1
sadd/comb copy/deep s3 copy/deep s3_id
sadd/comb copy/deep s3_id copy/deep s3_id


trait Shape {
    fn area(self) -> i32;
}


abstract class X {
  type A
  var B: A
  val C: A
  def D(a: A): A
}

trait Y {
  val x: X
}


const type: myInterf is sub object interface;

const func integer: method1 (in myInterf: interf, in float: aFloat) is DYNAMIC;
const func integer: method2 (in myInterf: interf, in string: name) is DYNAMIC;
const func integer: add (in myInterf: interf, in integer: a, in integer: b) is DYNAMIC;


#!/bin/sed -nrf
# Format: <master-pattern>\n<line1>\n<line1-as-pattern>\n<line2>\n<line2-as-pattern>...
# After reading whole file <master-pattern> contains max number of fields of max width each.

# If no $ at start or end of a line -- add them
/^\$/! s/^/$/
/\$$/! s/$/$/

# First line saved as three lines in hold space:
# <line1-as-pattern>\n<line1>\n<line1-as-pattern>
1{
 h
 s/[^$]/ /g
 H
 G
 x
 # Restart -- go to next line
 b
}

# For lines 2,3,...
H
# Current line -> pattern
# (each character replaced by constant symbol (e.g. space) so that we can count them)
s/[^$]/ /g
H
G
# Add two markers
s/\$/1$/
s/(\n[^$]*)\$/\12$/

# Compare patterns
:cmp
	s/(1\$([^$\n]*)([^$\n]*)[^2]*2\$\2)/\1\3/
	/1\$\n/ bout
	# Advance markers
	s/1(\$[^12$\n]*)/\11/
	s/2(\$[^12$\n]*)/\12/
	# Add one more field
	/^[^2]*2\$\n/{ s/^([^2]*)2\$\n/\12$$\n/; }
bcmp
:out
# Remove first line
s/[^\n]*\n//
# Remove 2$-marker
s/2\$/$/
x

${
# We are on the last line -- start printing
	x;
	# Add a line for aligned string
	s/^/\n/
	:nextline
	# Add marker again (only one this time)
	s/\$/1$/
	:align
		# 1. look up missing spaces,
		# 2. put first word of 2nd line before first newline adding missing spaces
		# 3. cut first word of 2nd and 3rd lines.
		# Replace \5\3 by \3\5 for RIGHT ALIGNMENT
		s/(\n[^\n]*)1\$([^$\n]*)([^$\n]*)\$([^\n]*\n)\$([^$\n]*)([^\n]*\n)\$\2\$/\5\3 \1$\2\31$\4\6$/
	talign
	# We ate 2nd and 3rd lines completely, except newlines -- remove them
	s/\$\n\$\n\$\n/$\n/
	# Print the first line in pattern space
	P
	# ... and remove it
	s/^[^\n]*//
	# Remove marker
	s/1\$/$/
	# If no more lines -- exit
	/\$\n\$$/q
	bnextline
}


$ include "seed7_05.s7i";

const array string: inputLines is [] (
    "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.");

const func array integer: computeColumnWidths (in array string: inputLines) is func
  result
    var array integer: columnWidths is 0 times 0;
  local
    var string: line is "";
    var array string: lineFields is 0 times "";
    var integer: index is 0;
  begin
    for line range inputLines do
      lineFields := split(line, "$");
      if length(lineFields) > length(columnWidths) then
        columnWidths &:= (length(lineFields) - length(columnWidths)) times 0;
      end if;
      for index range 1 to length(lineFields) do
        if length(lineFields[index]) > columnWidths[index] then
          columnWidths[index] := length(lineFields[index]);
        end if;
      end for;
    end for;
  end func;

const func string: center (in string: stri, in integer: length) is
  return ("" lpad (length - length(stri)) div 2 <& stri) rpad length;

const proc: main is func
  local
    var array integer: columnWidths is 0 times 0;
    var string: line is "";
    var array string: lineFields is 0 times "";
    var integer: index is 0;
  begin
    columnWidths := computeColumnWidths(inputLines);
    for line range inputLines do
      lineFields := split(line, "$");
      for index range 1 to length(lineFields) do
        # write(lineFields[index] rpad columnWidths[index] <& " "); # Left justify
        # write(lineFields[index] lpad columnWidths[index] <& " "); # Right justify
        write(center(lineFields[index], columnWidths[index]) <& " ");
      end for;
      writeln;
    end for;
  end func;


/*REXX program demonstrates a 3x3 sandpile model by addition with toppling & avalanches.*/
@.= 0;   size= 3                                 /*assign 0 to all grid cells; grid size*/
call init   1,      1 2 0    2 1 1    0 1 3      /*   "   grains of sand──► sandpile 1. */
call init   2,      2 1 3    1 0 1    0 1 0      /*   "      "    "   "  "     "     2  */
call init   3,      3 3 3    3 3 3    3 3 3      /*   "      "    "   "  "     "     3  */
call init 's3_id',  2 1 2    1 0 1    2 1 2      /*   "      "    "   "  "     "    3_id*/
call show   1                                    /*display sandpile  1  to the terminal.*/
call show   2                                    /*   "        "     2   "  "      "    */
call  add   1, 2, 'sum1',           'adding sandpile  s1  and  s2  yields:'
call show 'sum1'
call  add   2, 1, 'sum2',           'adding sandpile  s2  and  s1  yields:'
call show 'sum2'
call  eq? 'sum1', 'sum2'                         /*is  sum1  the same as  sum2 ?        */
call show   3
call show 's3_id'
call  add   3,     's3_id', 'sum3', 'adding sandpile  s3  and  s3_id  yields:'
call show 'sum3'
call  add 's3_id', 's3_id', 'sum4', 'adding sandpile  s3_id  and  s3_id  yields:'
call show 'sum4'
call  eq? 'sum4',  's3_id'                       /*is  sum4  the same as  s3_id ?       */
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
@get: procedure expose @.; parse arg grid,r,c    ;                      return @.grid.r.c
@set: procedure expose @.; parse arg grid,r,c,val;  @.grid.r.c= val;    return
tran: procedure; parse arg a;  if datatype(a,'W')  then a='s'a;         return a
/*──────────────────────────────────────────────────────────────────────────────────────*/
add:  parse arg x, y, t;    if t==''  then t= 'sum';  xx= tran(x);  yy= tran(y)
        do r=1  for size;   do c=1  for size;   @.t.r.c= @.xx.r.c  +  @.yy.r.c
                            end   /*c*/
        end   /*r*/;    say arg(4);             call norm t;            return
/*──────────────────────────────────────────────────────────────────────────────────────*/
eq?:  parse arg x, y;   xx= tran(x);      yy= tran(y);      ?= 1
        do r=1  for size;         do c=1  for size;         ?= ?  &  (@.xx.r.[email protected].yy.r.c)
                                  end   /*c*/
        end   /*r*/
      if ?  then say  'comparison of '      xx       " and "       yy':  same.'
            else say  'comparison of '      xx       " and "       yy':  not the same.'
      return
/*──────────────────────────────────────────────────────────────────────────────────────*/
init: parse arg x, $;   xx= tran(x);   #= 0;      pad= left('', 8);   ind= left('', 45)
        do r=1  for size;   do c=1  for size;     #= # + 1;           @.xx.r.c= word($, #)
                            end   /*c*/
        end   /*r*/;                              shows= 0;             return
/*──────────────────────────────────────────────────────────────────────────────────────*/
norm: procedure expose @. size; parse arg x;        xx= tran(x);            recurse= 0
        do r=1  for size;     do c=1  for size;     if @.xx.r.c<=size  then iterate
                              recurse= 1;              @.xx.r.c= @.xx.r.c - 4
                              call @set  xx, r-1, c  , @get(xx, r-1, c  )   +   1
                              call @set  xx, r+1, c  , @get(xx, r+1, c  )   +   1
                              call @set  xx, r  , c-1, @get(xx, r  , c-1)   +   1
                              call @set  xx, r  , c+1, @get(xx, r  , c+1)   +   1
                              end   /*c*/
        end   /*r*/;    if recurse  then call norm xx;                  return
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: parse arg x;  xx= tran(x);  say ind center("sandpile" xx,25,'─')  /*show the title*/
        do r=1  for size;  $=;      do c=1  for size;   $= $  @.xx.r.c  /*build a row.  */
                                    end   /*c*/
        say ind pad $                                                   /*display a row.*/
        end   /*r*/;     shows= shows + 1;     if shows==1  then say;   return


class A {
    # must be filled in by the class which will inherit it
    method abstract() { die 'Unimplemented' };

    # can be overridden in the class, but that's not mandatory
    method concrete() { say '# 42' };
}

class SomeClass << A {
    method abstract() {
        say "# made concrete in class"
    }
}

var obj = SomeClass.new;
obj.abstract();   # made concrete in class
obj.concrete();   # 42


    ! ABSTRACT HASH KEY TYPE ;
    LISTVAL CLASS HASHKEY;
    VIRTUAL:
        PROCEDURE HASH IS
            INTEGER PROCEDURE HASH;;
        PROCEDURE EQUALTO IS
            BOOLEAN PROCEDURE EQUALTO(K); REF(HASHKEY) K;;
    BEGIN
    END HASHKEY;


someClass class >> isAbstract
    ^ true

someClass class >> new
    self isAbstract ifTrue:[
        ^ self error:'trying to instantiate an abstract class'
    ].
    ^ super new

someClass >> method1
    ^ self subclassResponsibility


signature QUEUE = sig
  type 'a queue
  val empty : 'a queue
  val enqueue : 'a -> 'a queue -> 'a queue
  val dequeue : 'a queue -> ('a * 'a queue) option
end