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