// https://github.com/sCrypt-Inc/boilerplate/blob/master/contracts/ackermann.scrypt

contract Ackermann {
    int a; // a = 2
    int b; // b = 1

    static const int LOOPCOUNT = 14;

    function ackermann(int m, int n) : int {
        bytes stk = num2bin(m, 1);

        // run this function off chain to get the loop count and set it here
        // e.g., (2, 1) requires 14 loops, (3, 5) 42438
        loop (LOOPCOUNT) {
            if (len(stk) > 0) {
                bytes top = stk[0 : 1];
                m = unpack(top);

                // pop
                stk = stk[1 : len(stk)];

                if (m == 0) {
                    n = n + m + 1;
                }
                else if (n == 0) {
                    n++;
                    m--;
                    // push
                    stk = num2bin(m, 1) + stk;
                }
                else {
                    stk = num2bin(m - 1, 1) + stk;
                    stk = num2bin(m, 1) + stk;
                    n--;
                }
            }
        }

        return n;
    }

    // y = 5
    public function unlock(int y) {
        require(y == this.ackermann(this.a, this.b));
    }
}