#@name 2048 game logic
@inputs 
@outputs 
@persist 
@trigger 


function string string:tPrint() {
    local String = ""
    for (I = 1, 16) {
        String = String + This[I] + " "
        if (I % 4 == 0) { String = String + "\n" }
    }
    printColor(vec(255, 255, 255), String)
    return This
}

function string string:setChar( Index, String:string ) {
    return This:sub(1, Index - 1) + String + This:sub(Index + 1)
}

function string string:displaceLeft() {
    return This:replace("-", "") + This:replaceRE("%a", "")
}

function string string:displaceRight() {
    return This:replaceRE("%a", "") + This:replace("-", "")
}

function string string:convergeRight() {
    local String = ""
    for (I = 1, 4) {
        local Sub = This:sub((I - 1) * 4 + 1, I * 4):displaceRight()
        for (J = 4, 1, -1) {
            local Next = Sub[J - 1]
    
            if (Next == "-") { break }
            if (Next == Sub[J]) {
                Sub = Sub:setChar(J, toChar(toByte(Next) + 1)):setChar(J - 1, "-")
            }         
        }
        String = String + Sub:displaceRight()
    }
    return String
}

function string string:convergeLeft() {
    local String = ""
    for (I = 1, 4) {
        local Sub = This:sub((I - 1) * 4 + 1, I * 4):displaceLeft()
        for (J = 1, 4) {
            local Next = Sub[J + 1]
    
            if (Next == "-") { break }
            if (Next == Sub[J]) {
                Sub = Sub:setChar(J, toChar(toByte(Next) + 1)):setChar(J + 1, "-")
            }         
        }
        String = String + Sub:displaceLeft()
    }
    return String
}

function string string:convergeUp() {
    for (I = 1, 4) {
        local Sub = ""
        for (J = 1, 4) {
            Sub = Sub + This[J * 4 - I + 1]
        }

        Sub = Sub:displaceLeft()
        for (K = 1, 4) {
            local Next = Sub[K + 1]
    
            if (Next == "-") { break }
            if (Next == Sub[K]) {
                Sub = Sub:setChar(K, toChar(toByte(Next) + 1)):setChar(K + 1, "-")
            }             
        }

        Sub = Sub:displaceLeft()
        for (L = 1, 4) {
            This = This:setChar(L * 4 - I + 1, Sub[L])
        }
    }
    return This
}


function string string:convergeDown() {
    for (I = 1, 4) {
        local Sub = ""
        for (J = 1, 4) {
            Sub = Sub + This[J * 4 - I + 1]
        }

        Sub = Sub:displaceRight()
        for (K = 4, 1, -1) {
            local Next = Sub[K - 1]
    
            if (Next == "-") { break }
            if (Next == Sub[K]) {
                Sub = Sub:setChar(K, toChar(toByte(Next) + 1)):setChar(K - 1, "-")
            }             
        }

        Sub = Sub:displaceRight()
        for (L = 1, 4) {
            This = This:setChar(L * 4 - I + 1, Sub[L])
        }
    }
    return This
}

S = "--a-a-a--bb-----"

S:tPrint()
S:convergeDown():tPrint()
