Rebol3 Code Examplex


Abelian sandpile model/Identity

Simulate sandpile stabilization and compute the identity configuration.

Rebol [
    title: "Rosetta code: Abelian sandpile model/Identity"
    file:  %Abelian_sandpile_model-Identitys.r3
    url:   https://rosettacode.org/wiki/Abelian_sandpile_model/Identity
    note:  "Based on Red language solution"
]
sadd: context [
    ;; 'comb' adds two 3x3 piles cell by cell, then validates the result
    comb: function [pile1 [series!] pile2 [series!]] [
        ;; Loop over rows 1 to 3
        repeat r 3 [
            ;; Loop over columns 1 to 3
            repeat c 3 [
                ;; Add corresponding cell values from pile1 to pile2
                pile2/:r/:c: pile2/:r/:c + pile1/:r/:c
            ]
        ]
        ;; Validate and stabilize the resulting pile
        check pile2
    ]
    ;; 'check' ensures no cell exceeds threshold (4); if it does, it topples
    check: function [pile [series!]] [
        stable:   true  ;; Flag to track if pile is stable
        row: col: none  ;; Coordinates of any unstable cell
        ;; Scan the 3x3 grid for cells >= 4
        repeat r 3 [
            repeat c 3 [
                if pile/:r/:c >= 4 [
                    stable: false 
                    ;; Subtract threshold from the unstable cell
                    pile/:r/:c: pile/:r/:c - 4 
                    row: r col: c 
                    break  ;; Exit inner repeat when found
                ]
            ]
            unless stable [break]  ;; Exit outer repeat if unstable cell found
        ]
        ;; If no unstable cell was found, print final pile and exit
        if stable [
            print trim/with mold/only pile "[]"
            print ""
            exit
        ]
        ;; Distribute ("spill") grains from the unstable cell to neighbors
        spill pile row col
    ]
    ;; 'spill' distributes one grain to each valid neighbor of (r, c)
    spill: function [pile [series!] r [integer!] c [integer!]] [
        ;; Define neighbor offsets: right, up, left, down
        neigh: reduce [
            right: reduce [r c - 1] 
            up:    reduce [r + 1 c]
            left:  reduce [r c + 1] 
            down:  reduce [r - 1 c]   
        ]
        ;; For each neighbor coordinate pair 'n'
        foreach n neigh [
            ;; If neighbor cell exists (not off-grid), add one grain
            unless any [
                none? pile/(n/1)
                none? pile/(n/1)/(n/2)
            ][
                pile/(n/1)/(n/2): pile/(n/1)/(n/2) + 1
            ] 
        ]
        ;; Re-check pile for further toppling
        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]
]
print "Avalanche of topplings"
sadd/check copy/deep ex
print "Add s1 to s2"
sadd/comb copy/deep s1 copy/deep s2
print "Add s2 to s1"
sadd/comb copy/deep s2 copy/deep s1
print "Add s3 to s3_id"
sadd/comb copy/deep s3 copy/deep s3_id
print "Add s3_id to s3_id"
sadd/comb copy/deep s3_id copy/deep s3_id