Our sandpiles are based on a 3 by 3 rectangular grid giving nine areas that
contain a number from 0 to 3 inclusive. (The numbers are said to represent
grains of sand in each area of the sandpile).

E.g. s1 =

    
    1 2 0
    2 1 1
    0 1 3

and s2 =

    2 1 3
    1 0 1
    0 1 0

Addition on sandpiles is done by adding numbers in corresponding grid areas,
so for the above:

              1 2 0     2 1 3     3 3 3
    s1 + s2 = 2 1 1  +  1 0 1  =  3 1 2
              0 1 3     0 1 0     0 2 3

If the addition would result in more than 3 "grains of sand" in any area then
those areas cause the whole sandpile to become "unstable" and the sandpile
areas are "toppled" in an "avalanche" until the "stable" result is obtained.

Any unstable area (with a number >= 4), is "toppled" by loosing one grain of
sand to each of its four horizontal or vertical neighbours. Grains are lost
at the edge of the grid, but otherwise increase the number in neighbouring
cells by one, whilst decreasing the count in the toppled cell by four in each
toppling.

A toppling may give an adjacent area more than four grains of sand leading to
a chain of topplings called an "avalanche".
E.g.

    
    4 3 3     0 4 3     1 0 4     1 1 0     2 1 0
    3 1 2 ==> 4 1 2 ==> 4 2 2 ==> 4 2 3 ==> 0 3 3
    0 2 3     0 2 3     0 2 3     0 2 3     1 2 3

The final result is the stable sandpile on the right.

Note: The order in which cells are toppled does not affect the final result.

Task

 Create a class or datastructure and functions to represent and operate on sandpiles. 
 Confirm the result of the avalanche of topplings shown above
 Confirm that s1 + s2 == s2 + s1 # Show the stable results
 If s3 is the sandpile with number 3 in every grid area, and s3_id is the following sandpile:
    2 1 2  
    1 0 1  
    2 1 2

 Show that s3 + s3_id == s3
 Show that s3_id + s3_id == s3_id


Show confirming output here, with your examples.



References

 https://www.youtube.com/watch?v=1MtEUErz7Gg
 https://en.wikipedia.org/wiki/Abelian_sandpile_model


 
/* 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"
 