Rule 110

The Rule 110 cellular automaton is a 1-dimensional elementary CA, where a linear pattern of 0s and 1s evolves according to a simple set of rules. Whether a point in the pattern will be 0 or 1 in the new generation depends on its current value and on those of its two neighbors. The Rule 110 has the following set of rules:

Current pattern111110101100011010001000
New state for center cell01101110
contract rule110 {
    static const int N = 5; //size of board
    static const int N2 = 3; //size of board
    static bytes LIVE = b'01';
    static bytes DEAD = b'00';

    @state
    bytes board;
    public function play(int amount, SigHashPreimage txPreimage) {
        SigHashType sigHashType = SigHash.ANYONECANPAY | SigHash.SINGLE | SigHash.FORKID;
        // this ensures the preimage is for the current tx
        require(Tx.checkPreimageSigHashType(txPreimage, sigHashType));

        this.board = this.computeNewBoard(this.board);

        bytes newScriptCode = this.getStateScript();
        bytes output = Utils.buildOutput(newScriptCode, amount);

        require(hash256(output) == SigHash.hashOutputs(txPreimage));
    }

    function computeNewBoard(bytes board) : bytes {
        bytes res = b'';
        res += DEAD;
        loop (N2) : i {
            res += this.newState(board[i : i + 3]);
        }
        res += DEAD;
        return res;
    }
    
    function newState(bytes arg) : bytes {
        /*
          Current pattern            111    110    101    100    011    010    001    000
          New state for center cell     0     1     1    0     1     1     1     0
        */
        bytes a = arg[0 : 1];
        bytes b = arg[1 : 2];
        bytes c = arg[2 : 3];
        bytes res = LIVE;
        if (a == LIVE && b == LIVE && c == LIVE) {
            res = DEAD;
        }
        if (a == LIVE && b == DEAD && c == DEAD) {
            res = DEAD;
        }
        if (a == DEAD && b == DEAD && c == DEAD) {
            res = DEAD;
        }
        return res;
    }
}