Test block numbers.

Test block numbers.

pragma solidity ^0.4.4;

import "dapple/test.sol";
import "./blobstore.sol";
import "./blobstore_flags.sol";
import "./blobstore_proxy.sol";

/**
 * @title BlobStoreTest
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStoreTest is Test, BlobStoreFlags {

    BlobStoreRegistry blobStoreRegistry;
    BlobStore blobStore;
    BlobStoreProxy blobStoreProxy;

    function setUp() {
        blobStoreRegistry = new BlobStoreRegistry();
        blobStore = new BlobStore(blobStoreRegistry);
        blobStoreProxy = new BlobStoreProxy(blobStore);
    }

    function testThrowRegisterContractAgain() {
        blobStoreRegistry.register(blobStore.getContractId());
    }

    function testThrowBlobStoreNotRegistered() {
        blobStoreRegistry.getBlobStore(0);
    }

    function testBlobStoreRegistered() {
        assertEq(blobStoreRegistry.getBlobStore(blobStore.getContractId()), blobStore);
    }

    function testCreate() {
        bytes20 blobId0 = blobStore.create(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));
        assertEq(blobStore.getRevisionBlockNumber(blobId0, 0), block.number);

        bytes20 blobId1 = blobStore.create(UPDATABLE | ENFORCE_REVISIONS | RETRACTABLE | TRANSFERABLE | ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));
        assertEq(blobStore.getRevisionBlockNumber(blobId1, 0), block.number);

        assertFalse(blobId0 == blobId1);
    }

    function testThrowCreateWithNonceExistingNonce() {
        blobStore.createWithNonce(0, hex"00");
        blobStore.createWithNonce(0, hex"00");
    }

    function testCreateWithNonce() {
        bytes20 blobId0 = blobStore.createWithNonce(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));
        assertEq(blobStore.getRevisionBlockNumber(blobId0, 0), block.number);

        bytes20 blobId1 = blobStoreProxy.createWithNonce(0, hex"00");

        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), blobStoreProxy);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertFalse(blobStore.getUpdatable(blobId1));
        assertFalse(blobStore.getEnforceRevisions(blobId1));
        assertFalse(blobStore.getRetractable(blobId1));
        assertFalse(blobStore.getTransferable(blobId1));
        assertFalse(blobId0 == blobId1);
        assertEq(blobStore.getRevisionBlockNumber(blobId1, 0), block.number);

        blobId1 = blobStore.createWithNonce(UPDATABLE | ENFORCE_REVISIONS | RETRACTABLE | TRANSFERABLE | ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));
        assertEq(blobStore.getRevisionBlockNumber(blobId1, 0), block.number);
        assertFalse(blobId0 == blobId1);
    }

    function testThrowCreateWithNonceRetracted() {
        bytes20 blobId = blobStore.createWithNonce(RETRACTABLE, hex"00");
        blobStore.retract(blobId);
        blobStore.createWithNonce(RETRACTABLE, hex"00");
    }

    function testThrowCreateNewRevisionNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.createNewRevision(blobId, hex"00");
    }

    function testThrowCreateNewRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
    }

    function testCreateNewRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        uint revisionId = blobStore.createNewRevision(blobId, hex"00");
        assertEq(revisionId, 1);
        assertEq(blobStore.getRevisionCount(blobId), 2);
        assertEq(blobStore.getRevisionBlockNumber(blobId, 1), block.number);
    }

    function testThrowUpdateLatestRevisionNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.updateLatestRevision(blobId, hex"00");
    }

    function testThrowUpdateLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testThrowUpdateLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testUpdateLatestRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
        assertEq(blobStore.getRevisionBlockNumber(blobId, 0), block.number);
    }

    function testThrowRetractLatestRevisionNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStoreProxy.retractLatestRevision(blobId);
    }

    function testThrowRetractLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.setNotUpdatable(blobId);
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowRetractLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowRetractLatestRevisionDoesntHaveAdditionalRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testRetractLatestRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 3);
        blobStore.retractLatestRevision(blobId);
        assertEq(blobStore.getRevisionCount(blobId), 2);
    }

    function testThrowRestartNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.restart(blobId, hex"00");
    }

    function testThrowRestartNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.restart(blobId, hex"00");
    }

    function testThrowRestartEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.restart(blobId, hex"00");
    }

    function testRestart() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 3);
        blobStore.restart(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
        assertEq(blobStore.getRevisionBlockNumber(blobId, 0), block.number);
    }

    function testThrowRetractNotOwner() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStoreProxy.retract(blobId);
    }

    function testThrowRetractNotRetractable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.retract(blobId);
    }

    function testRetract() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStore.retract(blobId);
        assertEq(blobStore.getExists(blobId), false);
    }

    function testThrowTransferEnableNotTransferable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStoreProxy.transferEnable(blobId);
    }

    function testThrowTransferDisableNotEnabled() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.transferDisable(blobId);
    }

    function testThrowTransferNotTransferable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStoreProxy.transferEnable(blobId);
        blobStore.transfer(blobId, blobStoreProxy);
    }

    function testThrowTransferNotEnabled() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStore.transfer(blobId, blobStoreProxy);
    }

    function testThrowTransferDisabled() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.transferEnable(blobId);
        blobStoreProxy.transferDisable(blobId);
        blobStore.transfer(blobId, blobStoreProxy);
        assertEq(blobStore.getOwner(blobId), blobStoreProxy);
    }

    function testTransfer() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.transferEnable(blobId);
        blobStore.transfer(blobId, blobStoreProxy);
        assertEq(blobStore.getOwner(blobId), blobStoreProxy);
    }

    function testThrowDisownNotOwner() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.disown(blobId);
    }

    function testThrowDisownNotTransferable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.disown(blobId);
    }

    function testDisown() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        assertEq(blobStore.getOwner(blobId), this);
        blobStore.disown(blobId);
        assertEq(blobStore.getOwner(blobId), 0);
    }

    function testThrowSetNotUpdatableNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.setNotUpdatable(blobId);
    }

    function testSetNotUpdatable() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        assertTrue(blobStore.getUpdatable(blobId));
        blobStore.setNotUpdatable(blobId);
        assertEq(blobStore.getUpdatable(blobId), false);
    }

    function testThrowSetEnforceRevisionsNotOwner() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStoreProxy.setEnforceRevisions(blobId);
    }

    function testSetEnforceRevisions() {
        bytes20 blobId = blobStore.create(0, hex"00");
        assertEq(blobStore.getEnforceRevisions(blobId), false);
        blobStore.setEnforceRevisions(blobId);
        assertTrue(blobStore.getEnforceRevisions(blobId));
    }

    function testThrowSetNotRetractableNotOwner() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStoreProxy.setNotRetractable(blobId);
    }

    function testSetNotRetractable() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        assertTrue(blobStore.getRetractable(blobId));
        blobStore.setNotRetractable(blobId);
        assertEq(blobStore.getRetractable(blobId), false);
    }

    function testThrowSetNotTransferableNotOwner() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.setNotTransferable(blobId);
    }

    function testSetNotTransferable() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        assertTrue(blobStore.getTransferable(blobId));
        blobStore.setNotTransferable(blobId);
        assertEq(blobStore.getTransferable(blobId), false);
    }

}

pragma solidity ^0.4.4;

import "dapple/test.sol";
import "./blobstore.sol";
import "./blobstore_flags.sol";
import "./blobstore_proxy.sol";

/**
 * @title BlobStoreTest
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStoreTest is Test, BlobStoreFlags {

    BlobStoreRegistry blobStoreRegistry;
    BlobStore blobStore;
    BlobStoreProxy blobStoreProxy;

    function setUp() {
        blobStoreRegistry = new BlobStoreRegistry();
        blobStore = new BlobStore(blobStoreRegistry);
        blobStoreProxy = new BlobStoreProxy(blobStore);
    }

    function testThrowRegisterContractAgain() {
        blobStoreRegistry.register(blobStore.getContractId());
    }

    function testThrowBlobStoreNotRegistered() {
        blobStoreRegistry.getBlobStore(0);
    }

    function testBlobStoreRegistered() {
        assertEq(blobStoreRegistry.getBlobStore(blobStore.getContractId()), blobStore);
    }

    function testCreate() {
        bytes20 blobId0 = blobStore.create(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));

        bytes20 blobId1 = blobStore.create(UPDATABLE | ENFORCE_REVISIONS | RETRACTABLE | TRANSFERABLE | ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));

        assertFalse(blobId0 == blobId1);
    }

    function testThrowCreateWithNonceExistingNonce() {
        blobStore.createWithNonce(0, hex"00");
        blobStore.createWithNonce(0, hex"00");
    }

    function testCreateWithNonce() {
        bytes20 blobId0 = blobStore.createWithNonce(0, hex"00");
        assertTrue(blobStore.getExists(blobId0));
        assertEq(blobStore.getOwner(blobId0), this);
        assertEq(blobStore.getRevisionCount(blobId0), 1);
        assertFalse(blobStore.getUpdatable(blobId0));
        assertFalse(blobStore.getEnforceRevisions(blobId0));
        assertFalse(blobStore.getRetractable(blobId0));
        assertFalse(blobStore.getTransferable(blobId0));

        bytes20 blobId1 = blobStoreProxy.createWithNonce(0, hex"00");

        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), blobStoreProxy);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertFalse(blobStore.getUpdatable(blobId1));
        assertFalse(blobStore.getEnforceRevisions(blobId1));
        assertFalse(blobStore.getRetractable(blobId1));
        assertFalse(blobStore.getTransferable(blobId1));
        assertFalse(blobId0 == blobId1);

        blobId1 = blobStore.createWithNonce(UPDATABLE | ENFORCE_REVISIONS | RETRACTABLE | TRANSFERABLE | ANONYMOUS, hex"00");
        assertTrue(blobStore.getExists(blobId1));
        assertEq(blobStore.getOwner(blobId1), 0);
        assertEq(blobStore.getRevisionCount(blobId1), 1);
        assertTrue(blobStore.getUpdatable(blobId1));
        assertTrue(blobStore.getEnforceRevisions(blobId1));
        assertTrue(blobStore.getRetractable(blobId1));
        assertTrue(blobStore.getTransferable(blobId1));
        assertFalse(blobId0 == blobId1);
    }

    function testThrowCreateWithNonceRetracted() {
        bytes20 blobId = blobStore.createWithNonce(RETRACTABLE, hex"00");
        blobStore.retract(blobId);
        blobStore.createWithNonce(RETRACTABLE, hex"00");
    }

    function testThrowCreateNewRevisionNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.createNewRevision(blobId, hex"00");
    }

    function testThrowCreateNewRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
    }

    function testCreateNewRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        uint revisionId = blobStore.createNewRevision(blobId, hex"00");
        assertEq(revisionId, 1);
        assertEq(blobStore.getRevisionCount(blobId), 2);
    }

    function testThrowUpdateLatestRevisionNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.updateLatestRevision(blobId, hex"00");
    }

    function testThrowUpdateLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testThrowUpdateLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
    }

    function testUpdateLatestRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.updateLatestRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
    }

    function testThrowRetractLatestRevisionNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStoreProxy.retractLatestRevision(blobId);
    }

    function testThrowRetractLatestRevisionNotUpdatable() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.setNotUpdatable(blobId);
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowRetractLatestRevisionEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testThrowRetractLatestRevisionDoesntHaveAdditionalRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.retractLatestRevision(blobId);
    }

    function testRetractLatestRevision() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 3);
        blobStore.retractLatestRevision(blobId);
        assertEq(blobStore.getRevisionCount(blobId), 2);
    }

    function testThrowRestartNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.restart(blobId, hex"00");
    }

    function testThrowRestartNotUpdatable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.restart(blobId, hex"00");
    }

    function testThrowRestartEnforceRevisions() {
        bytes20 blobId = blobStore.create(UPDATABLE | ENFORCE_REVISIONS, hex"00");
        blobStore.restart(blobId, hex"00");
    }

    function testRestart() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        blobStore.createNewRevision(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 3);
        blobStore.restart(blobId, hex"00");
        assertEq(blobStore.getRevisionCount(blobId), 1);
    }

    function testThrowRetractNotOwner() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStoreProxy.retract(blobId);
    }

    function testThrowRetractNotRetractable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.retract(blobId);
    }

    function testRetract() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStore.retract(blobId);
        assertEq(blobStore.getExists(blobId), false);
    }

    function testThrowTransferEnableNotTransferable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStoreProxy.transferEnable(blobId);
    }

    function testThrowTransferDisableNotEnabled() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.transferDisable(blobId);
    }

    function testThrowTransferNotTransferable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStoreProxy.transferEnable(blobId);
        blobStore.transfer(blobId, blobStoreProxy);
    }

    function testThrowTransferNotEnabled() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStore.transfer(blobId, blobStoreProxy);
    }

    function testThrowTransferDisabled() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.transferEnable(blobId);
        blobStoreProxy.transferDisable(blobId);
        blobStore.transfer(blobId, blobStoreProxy);
        assertEq(blobStore.getOwner(blobId), blobStoreProxy);
    }

    function testTransfer() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.transferEnable(blobId);
        blobStore.transfer(blobId, blobStoreProxy);
        assertEq(blobStore.getOwner(blobId), blobStoreProxy);
    }

    function testThrowDisownNotOwner() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.disown(blobId);
    }

    function testThrowDisownNotTransferable() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStore.disown(blobId);
    }

    function testDisown() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        assertEq(blobStore.getOwner(blobId), this);
        blobStore.disown(blobId);
        assertEq(blobStore.getOwner(blobId), 0);
    }

    function testThrowSetNotUpdatableNotOwner() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        blobStoreProxy.setNotUpdatable(blobId);
    }

    function testSetNotUpdatable() {
        bytes20 blobId = blobStore.create(UPDATABLE, hex"00");
        assertTrue(blobStore.getUpdatable(blobId));
        blobStore.setNotUpdatable(blobId);
        assertEq(blobStore.getUpdatable(blobId), false);
    }

    function testThrowSetEnforceRevisionsNotOwner() {
        bytes20 blobId = blobStore.create(0, hex"00");
        blobStoreProxy.setEnforceRevisions(blobId);
    }

    function testSetEnforceRevisions() {
        bytes20 blobId = blobStore.create(0, hex"00");
        assertEq(blobStore.getEnforceRevisions(blobId), false);
        blobStore.setEnforceRevisions(blobId);
        assertTrue(blobStore.getEnforceRevisions(blobId));
    }

    function testThrowSetNotRetractableNotOwner() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        blobStoreProxy.setNotRetractable(blobId);
    }

    function testSetNotRetractable() {
        bytes20 blobId = blobStore.create(RETRACTABLE, hex"00");
        assertTrue(blobStore.getRetractable(blobId));
        blobStore.setNotRetractable(blobId);
        assertEq(blobStore.getRetractable(blobId), false);
    }

    function testThrowSetNotTransferableNotOwner() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        blobStoreProxy.setNotTransferable(blobId);
    }

    function testSetNotTransferable() {
        bytes20 blobId = blobStore.create(TRANSFERABLE, hex"00");
        assertTrue(blobStore.getTransferable(blobId));
        blobStore.setNotTransferable(blobId);
        assertEq(blobStore.getTransferable(blobId), false);
    }

}


new timestamp so anyone can draw the bet, index event

pragma solidity ^0.4.11;

import './governanceInterface.sol';

contract Bet is ProposalInterface{

  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
  modifier onlyArbiter() {
    require(msg.sender == address(arbiter));
    _;
  }
  modifier beforeTimestamp(uint timestamp) {
    require(block.timestamp < timestamp);
    _;
  }
  modifier afterTimestamp(uint timestamp) {
    require(block.timestamp >= timestamp);
    _;
  }
  modifier matchIsOpenOrUndecided() {
    require(betState == BET_STATES.OPEN || betState == BET_STATES.UNDECIDED);
    _;
  }
  modifier matchIsDecided() {
    require(betState == BET_STATES.TEAM_ZERO_WON ||
            betState == BET_STATES.TEAM_ONE_WON ||
            betState == BET_STATES.DRAW);
    _;
  }
  modifier betInSomeTeam() {
    require(betsToTeam0[msg.sender] > 0 || betsToTeam1[msg.sender] > 0);
    _;
  }

  enum BET_STATES {
    OPEN,
    TEAM_ZERO_WON,
    TEAM_ONE_WON,
    DRAW,
    UNDECIDED,
    CALLED_RESOLVER
  }

  BET_STATES public betState = BET_STATES.OPEN;
  address public owner; // Can be a parent contract
  GovernanceInterface public arbiter; // Governance account
  bool public isFeatured;
  string public team0Name;
  string public team1Name;
  string public description;
  string public category;
  uint public team0BetSum;
  uint public team1BetSum;
  mapping (address => uint) public betsToTeam0;
  mapping (address => uint) public betsToTeam1;

  uint public timestampMatchBegin;
  uint public timestampMatchEnd;
  uint public timestampArbiterDeadline;
  // Self-destruct is possible if time > timestampSelfDestructDeadline
  uint public timestampSelfDestructDeadline;

  uint8 public constant TAX = 10;
  uint constant TIMESTAMP_MARGIN = 1000;

  event NewBet(bool forTeam, address indexed from, uint amount);
  event StateChanged(BET_STATES state);

  function Bet(GovernanceInterface _arbiter, string _team0Name,
               string _team1Name, string _category,
               uint[] _timestamps
               ) {
    require(block.timestamp < _timestamps[0]);
    require(_timestamps[0] < _timestamps[1]);
    require(_timestamps[1] < _timestamps[2]);
    require(_timestamps[2] < _timestamps[3]);

    isFeatured = false;
    owner = msg.sender;
    arbiter = _arbiter;
    team0Name = _team0Name;
    team1Name = _team1Name;
    category = _category;
    timestampMatchBegin = _timestamps[0] - TIMESTAMP_MARGIN;
    timestampMatchEnd = _timestamps[1] + TIMESTAMP_MARGIN;
    timestampArbiterDeadline = _timestamps[2] + TIMESTAMP_MARGIN;
    timestampSelfDestructDeadline = _timestamps[3] + TIMESTAMP_MARGIN;
  }

  function __resolve(uint outcome)
    onlyArbiter()
    afterTimestamp(timestampMatchEnd)
    beforeTimestamp(timestampArbiterDeadline)
    matchIsOpenOrUndecided() {
    require(betState == BET_STATES.CALLED_RESOLVER);
    if (outcome == 1)
      betState = BET_STATES.TEAM_ZERO_WON;
    else if (outcome == 2)
      betState = BET_STATES.TEAM_ONE_WON;
    else if (outcome == 3)
      betState = BET_STATES.DRAW;
    else
      betState = BET_STATES.UNDECIDED;
    StateChanged(betState);
  }

  // Will create a Proposal on the arbiter
  function updateResult() payable
    matchIsOpenOrUndecided()
    afterTimestamp(timestampMatchEnd) {
    require(betState != BET_STATES.CALLED_RESOLVER);
    arbiter.addProposal(this, timestampArbiterDeadline);
    betState = BET_STATES.CALLED_RESOLVER;
  }

  function toggleFeatured() onlyOwner() {
    isFeatured = !isFeatured;
  }

  function modifyCategory(string newCategory) onlyOwner() {
    category = newCategory;
  }

  //
  function bet(bool forTeam) payable
    beforeTimestamp(timestampMatchBegin) {
    require(!arbiter.isMember(msg.sender));
    uint prevSum;

    if (forTeam == false) {
      // Cannot bet in two teams
      require(betsToTeam1[msg.sender] == 0);
      prevSum = team0BetSum;
      require((prevSum + msg.value) >= prevSum); // Overflow
      team0BetSum += msg.value;
      assert(team0BetSum >= prevSum);
      betsToTeam0[msg.sender] += msg.value;
    }
    else {
      // Cannot bet in two teams
      require(betsToTeam0[msg.sender] == 0);
      prevSum = team1BetSum;
      require((prevSum + msg.value) >= prevSum); // Overflow
      team1BetSum += msg.value;
      assert(team1BetSum >= prevSum);
      betsToTeam1[msg.sender] += msg.value;
    }

    NewBet(forTeam, msg.sender, msg.value);
  }

  // The commented code allows money withdraw before the match begins.
  // It was decided that this will not be allowed.
  function withdraw()
    afterTimestamp(timestampMatchEnd)
    matchIsDecided()
    {
    if (betState == BET_STATES.DRAW) {
      collectBet();
    }
    else {
      collectProfit();
    }
  }

  // Transfers the user's initial bet back
  function collectBet() internal betInSomeTeam() {
    uint amount;
    if (betsToTeam0[msg.sender] > 0) {
      amount = betsToTeam0[msg.sender];
      betsToTeam0[msg.sender] = 0;
      msg.sender.transfer(amount);
    }
    else { // if (betsToTeam1[msg.sender] > 0)
      amount = betsToTeam1[msg.sender];
      betsToTeam1[msg.sender] = 0;
      msg.sender.transfer(amount);
    }
  }

  // Transfers the user's profit
  function collectProfit() internal {
    require( ( betState == BET_STATES.TEAM_ZERO_WON && betsToTeam0[msg.sender] > 0 ) ||
             ( betState == BET_STATES.TEAM_ONE_WON && betsToTeam1[msg.sender] > 0 ) );

    uint bet = 0;
    uint sum = 0;
    uint profit = 0;

    if (betState == BET_STATES.TEAM_ZERO_WON && betsToTeam0[msg.sender] > 0) {
      bet = betsToTeam0[msg.sender];
      sum = team0BetSum;
      profit = team1BetSum;
    }
    else { // if (BET_STATES.bet_state == TEAM_ONE_WON && betsToTeam1[msg.sender] > 0)
      bet = betsToTeam1[msg.sender];
      sum = team1BetSum;
      profit = team0BetSum;
    }

    assert(bet <= sum);

    // Approach one:
    // We might lose precision, but no overflow
    var senderPc = bet / sum;
    assert(senderPc >= 0 && senderPc <= 1);

    var senderProfit = senderPc * profit;
    assert(senderProfit <= profit);

    // Approach two:
    // Better precision, since multiplication is done first, but may overflow
    //uint sender_profit = (bet * profit) / sum;

    var mulTax = (senderProfit * TAX);
    require(mulTax >= senderProfit); // Overflow
    var tax = mulTax / 100;
    assert(tax <= senderProfit);

    var notaxProfit = senderProfit;
    senderProfit -= tax;
    assert(senderProfit <= notaxProfit);

    owner.transfer(tax);
    collectBet();
    msg.sender.transfer(senderProfit);
  }

  /* After the arbiter deadline and before the self-destruct
   * deadline, anyone can set the bet state to DRAW.
   * this is in the unlikely event if the arbiter don't
   * decide in time, every one can collect the funds.
  */
  function close()
    afterTimestamp(timestampArbiterDeadline)
    beforeTimestamp(timestampSelfDestructDeadline) {
    betState = BET_STATES.DRAW;
  }

  /* Selfdestructs the bet and return what it has in the account
   * as a fee to the bet's owner.
   */
  function terminate()
    afterTimestamp(timestampSelfDestructDeadline) {
    selfdestruct(owner);
  }

  /* Fallback just throws now
   * Can do something, maybe increase the value of both pools
  */
  function () { require(false); }
}

pragma solidity ^0.4.11;

import './governanceInterface.sol';

contract Bet is ProposalInterface{

  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
  modifier onlyArbiter() {
    require(msg.sender == address(arbiter));
    _;
  }
  modifier beforeMatchBegun() {
    require(block.timestamp < timestampMatchBegin);
    _;
  }
  modifier afterMatchEnded() {
    require(block.timestamp >= timestampMatchEnd);
    _;
  }
  modifier beforeResolverCanCall() {
    require(block.timestamp < timestampArbiterDeadline);
    _;
  }
  modifier matchIsOpenOrUndecided() {
    require(betState == BET_STATES.OPEN || betState == BET_STATES.UNDECIDED);
    _;
  }
  modifier matchIsDecided() {
    require(betState == BET_STATES.TEAM_ZERO_WON ||
            betState == BET_STATES.TEAM_ONE_WON ||
            betState == BET_STATES.DRAW);
    _;
  }
  modifier betInSomeTeam() {
    require(betsToTeam0[msg.sender] > 0 || betsToTeam1[msg.sender] > 0);
    _;
  }

  enum BET_STATES {
    OPEN,
    TEAM_ZERO_WON,
    TEAM_ONE_WON,
    DRAW,
    UNDECIDED,
    CALLED_RESOLVER
  }

  BET_STATES public betState = BET_STATES.OPEN;
  address public owner; // Can be a parent contract
  GovernanceInterface public arbiter; // Governance account
  bool public isFeatured;
  string public team0Name;
  string public team1Name;
  string public description;
  string public category;
  uint public team0BetSum;
  uint public team1BetSum;
  mapping (address => uint) public betsToTeam0;
  mapping (address => uint) public betsToTeam1;

  uint public timestampMatchBegin;
  uint public timestampMatchEnd;
  // Self-destruct is possible if time > timestampArbiterDeadline
  uint public timestampArbiterDeadline;

  uint8 public constant TAX = 10;
  uint constant TIMESTAMP_MARGIN = 1000;

  event NewBet(bool forTeam, address from, uint amount);
  event StateChanged(BET_STATES state);

  function Bet(GovernanceInterface _arbiter, string _team0Name,
               string _team1Name, string _category,
               uint[] _timestamps
               ) {
    require(block.timestamp < _timestamps[0]);
    require(_timestamps[0] < _timestamps[1]);
    require(_timestamps[1] < _timestamps[2]);

    isFeatured = false;
    owner = msg.sender;
    arbiter = _arbiter;
    team0Name = _team0Name;
    team1Name = _team1Name;
    category = _category;
    timestampMatchBegin = _timestamps[0] - TIMESTAMP_MARGIN;
    timestampMatchEnd = _timestamps[1] + TIMESTAMP_MARGIN;
    timestampArbiterDeadline = _timestamps[2] + TIMESTAMP_MARGIN;
  }

  function __resolve(uint outcome)
    onlyArbiter()
    afterMatchEnded()
    beforeResolverCanCall()
    matchIsOpenOrUndecided() {
    require(betState == BET_STATES.CALLED_RESOLVER);
    if (outcome == 1)
      betState = BET_STATES.TEAM_ZERO_WON;
    else if (outcome == 2)
      betState = BET_STATES.TEAM_ONE_WON;
    else if (outcome == 3)
      betState = BET_STATES.DRAW;
    else
      betState = BET_STATES.UNDECIDED;
    StateChanged(betState);
  }

  // Will create a Proposal on the arbiter
  function updateResult() payable
    matchIsOpenOrUndecided()
    afterMatchEnded() {
    require(betState != BET_STATES.CALLED_RESOLVER);
    arbiter.addProposal(this, timestampArbiterDeadline);
    betState = BET_STATES.CALLED_RESOLVER;
  }

  function toggleFeatured() onlyOwner() {
    isFeatured = !isFeatured;
  }

  function modifyCategory(string newCategory) onlyOwner() {
    category = newCategory;
  }

  //
  function bet(bool forTeam) payable
    beforeMatchBegun() {
    require(!arbiter.isMember(msg.sender));
    uint prevSum;

    if (forTeam == false) {
      // Cannot bet in two teams
      require(betsToTeam1[msg.sender] == 0);
      prevSum = team0BetSum;
      require((prevSum + msg.value) >= prevSum); // Overflow
      team0BetSum += msg.value;
      assert(team0BetSum >= prevSum);
      betsToTeam0[msg.sender] += msg.value;
    }
    else {
      // Cannot bet in two teams
      require(betsToTeam0[msg.sender] == 0);
      prevSum = team1BetSum;
      require((prevSum + msg.value) >= prevSum); // Overflow
      team1BetSum += msg.value;
      assert(team1BetSum >= prevSum);
      betsToTeam1[msg.sender] += msg.value;
    }

    NewBet(forTeam, msg.sender, msg.value);
  }

  // The commented code works allows money withdraw before the match begins.
  // It was decided that this will not be allowed.
  function withdraw()
    afterMatchEnded()
    matchIsDecided()
    {
    if (betState == BET_STATES.DRAW) {
      collectBet();
    }
    else {
      collectProfit();
    }
  }

  // Transfers the user's initial bet back
  function collectBet() internal betInSomeTeam() {
    uint amount;
    if (betsToTeam0[msg.sender] > 0) {
      amount = betsToTeam0[msg.sender];
      betsToTeam0[msg.sender] = 0;
      msg.sender.transfer(amount);
    }
    else { // if (betsToTeam1[msg.sender] > 0)
      amount = betsToTeam1[msg.sender];
      betsToTeam1[msg.sender] = 0;
      msg.sender.transfer(amount);
    }
  }

  // Transfers the user's profit
  function collectProfit() internal {
    require( ( betState == BET_STATES.TEAM_ZERO_WON && betsToTeam0[msg.sender] > 0 ) ||
             ( betState == BET_STATES.TEAM_ONE_WON && betsToTeam1[msg.sender] > 0 ) );

    uint bet = 0;
    uint sum = 0;
    uint profit = 0;

    if (betState == BET_STATES.TEAM_ZERO_WON && betsToTeam0[msg.sender] > 0) {
      bet = betsToTeam0[msg.sender];
      sum = team0BetSum;
      profit = team1BetSum;
    }
    else { // if (BET_STATES.bet_state == TEAM_ONE_WON && betsToTeam1[msg.sender] > 0)
      bet = betsToTeam1[msg.sender];
      sum = team1BetSum;
      profit = team0BetSum;
    }

    assert(bet <= sum);

    // Approach one:
    // We might lose precision, but no overflow
    var senderPc = bet / sum;
    assert(senderPc >= 0 && senderPc <= 1);

    var senderProfit = senderPc * profit;
    assert(senderProfit <= profit);

    // Approach two:
    // Better precision, since multiplication is done first, but may overflow
    //uint sender_profit = (bet * profit) / sum;

    var mulTax = (senderProfit * TAX);
    require(mulTax >= senderProfit); // Overflow
    var tax = mulTax / 100;
    assert(tax <= senderProfit);

    var notaxProfit = senderProfit;
    senderProfit -= tax;
    assert(senderProfit <= notaxProfit);

    owner.transfer(tax);
    collectBet();
    msg.sender.transfer(senderProfit);
  }

  function close() {
    require(block.timestamp > timestampArbiterDeadline);
    selfdestruct(owner);
  }

  /* Fallback just throws now
   * Can do something, maybe increase the value of both pools
  */
  function () { require(false); }
}


Platform Registry contract draft

Platform Registry contract draft

pragma solidity ^0.4.15;
import './TokenHolder.sol';
import './interfaces/IERC20Token.sol';

/**
    @dev The Platform Registry allows Trusted Platforms to register globally for linking wallets to their API
    A fee is charged for registering a platform on the registry
    Fees may be withdrawn by the registry owner using withdrawTokens
*/
contract PlatformRegistry is TokenHolder {

///////////////////////////////////////// VARIABLE INITIALIZATION /////////////////////////////////////////

    struct Platform {
        string url;
        string name;
        string description;
        address owner;
    }

    uint256 public lastFeeChanged = 0;              // Last timestamp the fee was updated
    uint256 public fee = 80000000000000000000;      // 80 ENJ fee, may be adjusted
    address public tokenAddress = 0x0;              // address of the Enjin Coin token
    IERC20Token enjinCoin;
    Platform[] platforms;

///////////////////////////////////////// EVENTS /////////////////////////////////////////

    event Registered(uint256 indexed id, string url, string name, string description, address owner);
    event Unregistered(uint256 indexed id, address owner);
    event Updated(uint256 indexed id);

///////////////////////////////////////// MODIFIERS /////////////////////////////////////////

    // Ensure 14 days have passed before allowing fee to be changed
    modifier feeTimeLock { if (lastFeeChanged != 0 && lastFeeChanged + (14 days) > now) return; _; }

    // Ensure new fee is within 10% of existing fee
    modifier feeAmountLimit(uint256 _fee) { if (_fee * 10 > fee * 11 || _fee * 10 < fee * 9) return; _; }

    // Only allow the Platform Owner/Creator to do something
    modifier onlyPlatformOwner(uint256 _id) { if (platforms[_id].owner != msg.sender) return; _; }

///////////////////////////////////////// OWNER FUNCTIONS /////////////////////////////////////////

    function setFee(uint256 _fee) ownerOnly feeTimeLock feeAmountLimit {
        fee = _fee;
        lastFeeChanged = now;
    }

    function setToken(address _tokenAddress) validAddress(_tokenAddress) ownerOnly {
        enjinCoin = IERC20Token(_tokenAddress);
    }

///////////////////////////////////////// PUBLIC FUNCTIONS /////////////////////////////////////////

    function register(string _url, string _name, string _description) returns (bool) {
        require(enjinCoin.allowance(msg.sender, this) >= fee);

        // Transfer fee from registrant to registry contract
        enjinCoin.transferFrom(msg.sender, this, fee);

        platforms.push(Platform(_url, _name, _description, msg.sender));
        Registered(platforms.length - 1, _url, _name, _description, msg.sender);
        return true;
    }

    function unregister(uint256 _id) onlyPlatformOwner(_id) {
        Unregistered(_id, platforms[_id].owner);
        delete platforms[_id];
    }

    function setPlatformOwner(uint256 _id, address _newOwner) onlyPlatformOwner(_id) validAddress(_newOwner) {
        platforms[_id].owner = _newOwner;
        Updated(_id);
    }

    function setPlatformUrl(uint256 _id, string _url) onlyPlatformOwner(_id) {
        platforms[_id].url = _url;
        Updated(_id);
    }

    function setPlatformName(uint256 _id, string _name) onlyPlatformOwner(_id) {
        platforms[_id].name = _name;
        Updated(_id);
    }

    function setPlatformDescription(uint256 _id, string _name) onlyPlatformOwner(_id) {
        platforms[_id].description = _description;
        Updated(_id);
    }

///////////////////////////////////////// CONSTANT FUNCTIONS /////////////////////////////////////////

    function platformCount() constant returns (uint256) {
        return platforms.length;
    }

    function platform(uint256 _id) constant returns (string url, string name, string description, address owner) {
        var p = platforms[_id];
        url = p.url;
        name = p.name;
        description = p.description;
        owner = p.owner;
    }
}

error: pathspec 'solidity/contracts/PlatformRegistry.sol' did not match any file(s) known to git


Add Second player must match bet.

Add Second player must match bet.

The second player can now only join, if they at least matched the value of
the game. If they didnt, the contract throws.

/**
 * Chess contract
 * Stores any amount of games with two players and current state.
 * State encoding:
 *    positive numbers for white, negative numbers for black
 *    for details, see
 *    https://github.com/ise-ethereum/on-chain-chess/wiki/Chess-board-representation
 */

 contract Chess {
    bytes constant defaultState = '\x04\x06\x05\x03\x02\x05\x06\x04\x08\x08\x08\x0c\x08\x08\x08\x08\x07\x07\x07\x07\x07\x07\x07\x07\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x09\x09\x09\x09\x09\x09\x09\x09\x08\x08\x08\x08\x08\x08\x08\x08\x0c\x0a\x0b\x0d\x0e\x0b\x0a\x0c\x08\x08\x08\x7c\x08\x08\x08\x08';

    bool debug; // If contract is deployed in debug mode, some debug features are enabled

    modifier debugOnly {
        if (!debug)
            throw;
        _
    }

    struct Game {
        address player1;
        address player2;
        string player1Alias;
        string player2Alias;
        address nextPlayer;
        address playerWhite; // Player that is white in this game
        address winner;
        uint value; // What this game is worth ether paid into the game

        int8[128] state;
    }

    mapping (bytes32 => Game) public games;
    mapping (address => mapping (int => bytes32)) public gamesOfPlayers;
    mapping (address => int) public numberGamesOfPlayers;

    // stack of open game ids
    mapping (bytes32 => bytes32) public openGameIds;
    bytes32 public head;

    /* Flags needed for validation
     * Usage e.g. Flags(Flag.FLAG_NAME)
     * Directions(Direction.UP)
     */
    enum Player { WHITE, BLACK }
    enum Direction { UP, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT }
    bytes constant c_Directions = "\x30\x31\x41\x51\x50\x4f\x3f\x2f";
    enum Piece { BLACK_KING, BLACK_QUEEN, BLACK_ROOK, BLACK_BISHOP, BLACK_KNIGHT, BLACK_PAWN, EMPTY, WHITE_PAWN, WHITE_KNIGHT, WHITE_BISHOP, WHITE_ROOK, WHITE_QUEEN, WHITE_KING }
    enum Flag { WHITE_KING_POS, BLACK_KING_POS, CURRENT_PLAYER, WHITE_LEFT_CASTLING, WHITE_RIGHT_CASTLING, BLACK_LEFT_CASTLING, BLACK_RIGHT_CASTLING, BLACK_EN_PASSANT, WHITE_EN_PASSANT}
    bytes constant c_Flags = "\x7b\x0b\x38\x4e\x4f\x3e\x3f\x3d\x4d\x3c\x4c";
    function Flags(Flag i) constant internal returns (uint) {
       return uint(c_Flags[uint(i)]);
    }
    function Pieces(Piece i) constant internal returns (int8) {
        return -6 + int8(uint(i));
    }
    function Directions(Direction i) constant internal returns (int8) {
        return -64 + int8(c_Directions[uint(i)]);
    }
    function Players(Player p) constant internal returns (int8) {
        if (p == Player.WHITE) {
            return 1;
        }
        return -1;
    }

    bytes constant knightMoves = '\x1f\x21\x2e\x32\x4e\x52\x5f\x61';

    function Chess(bool enableDebugging) {
        debug = enableDebugging;
        head = 'end';
    }

    event GameInitialized(bytes32 indexed gameId, address indexed player1, string player1Alias, address playerWhite);
    event GameJoined(bytes32 indexed gameId, address indexed player1, string player1Alias, address indexed player2, string player2Alias, address playerWhite);

    event GameStateChanged(bytes32 indexed gameId, int8[128] state);
    event Move(bytes32 indexed gameId, address indexed player, uint256 fromIndex, uint256 toIndex);
    event GameEnded(bytes32 indexed gameId, address indexed winner);

    event DebugInts(string message, int value1, int value2, int value3);

    /**
     * Convenience function to set a flag
     * Usage: setFlag(gameId, Flag.BLACK_KING_POS, 4);
     */

    function setFlag(bytes32 gameId, Flag flag, int value) internal {
        games[gameId].state[Flags(flag)] = int8(value);
    }

    /**
     * Convenience function to set a flag
     * Usage: getFlag(gameId, Flag.BLACK_KING_POS);
     */
    function getFlag(bytes32 gameId, Flag flag) internal returns (int8) {
        return games[gameId].state[Flags(flag)];

    }

    /**
     * Initialize a new game
     * string player1Alias: Alias of the player creating the game
     * bool playAsWhite: Pass true or false depending on if the creator will play as white
     */
    function initGame(string player1Alias, bool playAsWhite) public {
        // Generate game id based on player's addresses and current block number
        bytes32 gameId = sha3(msg.sender, block.number);

        // Initialize participants
        games[gameId].player1 = msg.sender;
        games[gameId].player1Alias = player1Alias;

        // Initialize game value
        games[gameId].value = 0;
        games[gameId].value = msg.value;
        // Initialize state

        for (uint i = 0; i < 128; i++) {
            // Read defaultState bytes string, which is offset by 8 to be > 0
            games[gameId].state[i] = int8(defaultState[i]) - 8;
        }

        if (playAsWhite) {
            // Player 1 will play as white
            games[gameId].playerWhite = msg.sender;

            // Game starts with White, so here player 1
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Add game to gamesOfPlayers
        gamesOfPlayers[msg.sender][numberGamesOfPlayers[msg.sender]] = gameId;
        numberGamesOfPlayers[msg.sender]++;

        // Add to openGameIds
        openGameIds[gameId] = head;
        head = gameId;

        // Sent notification events
        GameInitialized(gameId, games[gameId].player1, player1Alias, games[gameId].playerWhite);
        GameStateChanged(gameId, games[gameId].state);
    }

    /**
     * Join an initialized game
     * bytes32 gameId: ID of the game to join
     * string player2Alias: Alias of the player that is joining
     */
    function joinGame(bytes32 gameId, string player2Alias) public {

        // Check that this game does not have a second player yet
        if (games[gameId].player2 != 0) {
            throw;
        }

        // throw if the second player did not at least match the bet.
        if (games[gameID].value > msg.value) {
            throw;
        }
        else {
            games[gameID].value += msg.value;
        }

        games[gameId].player2 = msg.sender;
        games[gameId].player2Alias = player2Alias;

        // If the other player isn't white, player2 will play as white
        if (games[gameId].playerWhite == 0) {
            games[gameId].playerWhite = msg.sender;
            // Game starts with White, so here player2
            games[gameId].nextPlayer = games[gameId].player2;
        }

        // Add game to gamesOfPlayers
        gamesOfPlayers[msg.sender][numberGamesOfPlayers[msg.sender]] = gameId;
        numberGamesOfPlayers[msg.sender]++;

        // Remove from openGameIds
        if (head == gameId) {
            head = openGameIds[head];

            openGameIds[gameId] = 0;
        } else {
            for (var g = head; g != 'end' && openGameIds[g] != 'end'; g = openGameIds[g]) {
                if (openGameIds[g] == gameId) {
                    openGameIds[g] = openGameIds[gameId];
                    openGameIds[gameId] = 0;
                    break;
                }
            }
        }

        GameJoined(gameId, games[gameId].player1, games[gameId].player1Alias, games[gameId].player2, player2Alias, games[gameId].playerWhite);
    }

    /* Explicity set game state. Only in debug mode */
    function setGameState(bytes32 gameId, int8[128] state, address nextPlayer) debugOnly public {
        games[gameId].state = state;
        games[gameId].nextPlayer = nextPlayer;
        GameStateChanged(gameId, games[gameId].state);
    }

    /**
    * Allows the winner of a game to claim their ether
    * bytes32 gameId: ID of the game they have won
    */
    function claimWin(bytes32 gameId) public {

    }

    /* validates a move and executes it */
    function move(bytes32 gameId, uint256 fromIndex, uint256 toIndex) public {
        // Check that it is this player's turn
        if (games[gameId].nextPlayer != msg.sender) {
            throw;
        }

        int8 currentPlayerColor;
        if (msg.sender == games[gameId].playerWhite) {
            currentPlayerColor = Players(Player.WHITE);
        } else {
            currentPlayerColor = Players(Player.BLACK);
        }

        int8 fromFigure = games[gameId].state[fromIndex];
        int8 toFigure = games[gameId].state[toIndex];

        // Simple sanity checks
        sanityCheck(fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

        // Check if move is technically possible
        if (!validateMove(gameId, fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor)) {
            throw;
        }

        // For all pieces except knight, check if way is free
        if (abs(fromFigure) != uint(Pieces(Piece.WHITE_KNIGHT))) {
            // In case of king, it will check that he is not in check on any of the fields he moves over
            bool checkForCheck = abs(fromFigure) == uint(Pieces(Piece.WHITE_KING));
            checkWayFree(gameId, fromIndex, toIndex, currentPlayerColor, checkForCheck);
        }

        // Make the move
        makeMove(gameId, fromIndex, toIndex, fromFigure, toFigure);

        // Check legality (player's own king may not be in check after move)
        checkLegality(gameId, fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

        // Set nextPlayer
        if (msg.sender == games[gameId].player1) {
            games[gameId].nextPlayer = games[gameId].player2;
        } else {
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Send events
        Move(gameId, msg.sender, fromIndex, toIndex);
        GameStateChanged(gameId, games[gameId].state);
    }

    function sanityCheck(uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 currentPlayerColor) internal {
        // check that move is within the field
        if (toIndex & 0x88 != 0 || fromIndex & 0x88 != 0) {
            throw;
        }

        // check that from and to are distinct
        if (fromIndex == toIndex) {
            throw;
        }

        // check if the toIndex is empty (= is 0) or contains an enemy figure ("positive" * "negative" = "negative")
        // --> this only allows captures (negative results)  or moves to empty fields ( = 0)
        if (fromFigure * toFigure > 0) {
            throw;
        }

        // check if mover of the figure is the owner of the figure
        // also check if there is a figure at fromIndex to move (fromFigure != 0)
        if (currentPlayerColor * fromFigure <= 0) {
            throw;
        }
    }

    /**
     * Validates if a move is technically (not legally) possible,
     * i.e. if piece is capable to move this way
     */
    function validateMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 movingPlayerColor) returns (bool) {
        int8 direction = getDirection(fromIndex, toIndex);
        bool isDiagonal = !(abs(direction) == 16 || abs(direction) == 1);

        if (debug) {
            DebugInts('validateMove. fromFigure, toFigure, direction', int(fromFigure), int(fromFigure), int(direction));
        }

        // Kings
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_KING))) {
            // Normal move
            if (int(fromIndex) + direction == int(toIndex)) {
                return true;
            }
            // Castling
            if (checkForCheck(gameId, fromIndex, movingPlayerColor)) {
                // Cannot move if already in check
                return false;
            }
            if (fromFigure == Pieces(Piece.BLACK_KING)) {
                if (4 == fromIndex && toFigure == 0) {
                    if (toIndex == 2 && getFlag(gameId, Flag.BLACK_LEFT_CASTLING) >= 0) {
                        return true;
                    }
                    if (toIndex == 6 && getFlag(gameId, Flag.BLACK_RIGHT_CASTLING) >= 0) {
                        return true;
                    }
                }
            }
            if (fromFigure == Pieces(Piece.WHITE_KING)) {
                if (116 == fromIndex && toFigure == 0) {
                    if (toIndex == 114 && getFlag(gameId, Flag.WHITE_LEFT_CASTLING) >= 0) {
                        return true;
                    }
                    if (toIndex == 118 && getFlag(gameId, Flag.WHITE_RIGHT_CASTLING) >= 0) {
                        return true;
                    }
                }
            }

            return false;
        }

        // Bishops, Queens, Rooks
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_BISHOP)) ||
            abs(fromFigure) == uint(Pieces(Piece.WHITE_QUEEN)) ||
            abs(fromFigure) == uint(Pieces(Piece.WHITE_ROOK))) {

            // Bishop can only walk diagonally, Rook only non-diagonally
            if (!isDiagonal && abs(fromFigure) == uint(Pieces(Piece.WHITE_BISHOP)) ||
                isDiagonal && abs(fromFigure) == uint(Pieces(Piece.WHITE_ROOK))) {
                return false;
            }

            // Traverse all fields in direction
            int temp = int(fromIndex);
            // walk in direction while inside board to find toIndex
            while (temp & 0x88 == 0) {
                if (uint(temp) == toIndex) {
                    return true;
                }
                temp += direction;
            }

            return false;
        }

        // Pawns
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_PAWN))) {
            // Black can only move in positive, White negative direction
            if (fromFigure == Pieces(Piece.BLACK_PAWN) && direction < 0 ||
                fromFigure == Pieces(Piece.WHITE_PAWN) && direction > 0) {
                return false;
            }
            // Forward move
            if (!isDiagonal) {
                // no horizontal movement allowed
                if (abs(direction) < 2) {
                    return false;
                }
                // simple move
                if (int(fromIndex) + direction == int(toIndex)) {
                    if(toFigure == Pieces(Piece.EMPTY)){
                        return true;
                    }

                }
                // double move
                if (int(fromIndex) + direction + direction == int(toIndex)) {
                    // Can only do double move starting form specific ranks
                    int rank = int(fromIndex/16);
                    if (1 == rank || 6 == rank) {
                        if(toFigure == Pieces(Piece.EMPTY)){
                            return true;
                        }
                    }
                }
                return false;
            }
            // diagonal move
            if (int(fromIndex) + direction == int(toIndex)) {
                // if empty, the en passant flag needs to be set
                if (toFigure * fromFigure == 0) {
                    if (fromFigure == Pieces(Piece.BLACK_PAWN) &&
                        getFlag(gameId, Flag.WHITE_EN_PASSANT) == int(toIndex) ||
                        fromFigure == Pieces(Piece.WHITE_PAWN) &&
                        getFlag(gameId, Flag.BLACK_EN_PASSANT) == int(toIndex)) {
                        return true;
                    }
                    return false;
                }
                // If not empty
                return true;
            }

            return false;
        }

        // Knights
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_KNIGHT))) {
            for (uint i; i < 8; i++) {
                if (int(fromIndex) + int(knightMoves[i]) - 64 == int(toIndex)) {
                    return true;
                }
            }
            return false;
        }

        return false;

    }

    /**
     * Checks if the way between fromIndex and toIndex is unblocked
     */
    function checkWayFree(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 currentPlayerColor, bool shouldCheckForCheck) internal {
        int8 direction = getDirection(fromIndex, toIndex);
        int currentIndex = int(fromIndex) + direction;

        // as long as we do not reach the desired position walk in direction and check
        while (int(toIndex) != currentIndex) {
            // we reached the end of the field
            if (currentIndex & 0x88 != 0) {
                throw;
            }
            // the path is blocked
            if (games[gameId].state[uint(currentIndex)] != 0) {
                throw;
            }
            // Check for check in case of king
            if (shouldCheckForCheck && checkForCheck(gameId, uint(currentIndex), currentPlayerColor)) {
                throw;
            }
            currentIndex = currentIndex + direction;
        }
        return;
    }

    function checkForCheck(bytes32 gameId, uint256 kingIndex, int8 currentPlayerColor) internal returns (bool) {

        //get Position of King
       // int8 kingIndex = getOwnKing(gameId, currentPlayerColor);

        // look in every direction whether there is an enemy figure that checks the king
        for(uint dir = 0; dir < 8; dir ++){
          // get the first Figure in this direction. Threat of Knight does not change through move of fromFigure.
          // All other figures can not jump over figures. So only the first figure matters.
          int8 firstFigureIndex = getFirstFigure(gameId, Directions(Direction(dir)),int8(kingIndex));

          // if we found a figure in the danger direction
          if (firstFigureIndex != -1) {
              int8 firstFigure = games[gameId].state[uint(firstFigureIndex)];

              // if its an enemy
              if (firstFigure * currentPlayerColor > 0) {
                  // check if the enemy figure can move to the field of the king
                  int8 kingFigure = Pieces(Piece.BLACK_KING)* currentPlayerColor;
                  if (validateMove(gameId, uint256(firstFigureIndex), uint256(kingIndex), firstFigure, kingFigure, currentPlayerColor)) {
                      // it can
                      return true; // king is checked
                  }
              }

          }
        }

        //Knights
        // Knights can jump over figures. So they need to be tested seperately with every possible move.
        for(uint move = 0; move < 8; move ++){
            // currentMoveIndex: where knight could start with move that checks king
            int8 currentMoveIndex = int8(kingIndex) + int8(knightMoves[move]);

            // if inside the board
            if(uint(currentMoveIndex) & 0x88 == 0){

                // get Figure at currentMoveIndex
                int8 currentFigure = Pieces(Piece(currentMoveIndex));

                // if it is an enemy knight, king can be checked
                if(currentFigure * currentPlayerColor == Pieces(Piece.WHITE_KNIGHT)){
                    return true; // king is checked
                }
            }
        }

        return false; // king is not checked
    }

    function getDirection(uint256 fromIndex, uint256 toIndex) constant internal returns (int8) {
        // check if the figure is moved up or left of its origin
        bool isAboveLeft = fromIndex > toIndex;

        // check if the figure is moved in an horizontal plane
        // this code works because there is an eight square difference between the horizontal panes (the offboard)
        bool isSameHorizontal = (abs(int256(fromIndex) - int256(toIndex)) < (8));

        // check if the figure is moved in a vertical line
        bool isSameVertical = (fromIndex%8 == toIndex%8);

        // check if the figure is moved to the left of its origin
        bool isLeftSide = (fromIndex%8 > toIndex%8);

        /*Check directions*/
        if (isAboveLeft) {
            if (isSameVertical) {
                return Directions(Direction.UP);
            }
            if (isSameHorizontal) {
                return Directions(Direction.LEFT);
            }
            if (isLeftSide) {
                return Directions(Direction.UP_LEFT);
            } else {
                return Directions(Direction.UP_RIGHT);
            }
        } else {
            if (isSameVertical) {
                return Directions(Direction.DOWN);
            }
            if (isSameHorizontal) {
                return Directions(Direction.RIGHT);
            }
            if (isLeftSide) {
                return Directions(Direction.DOWN_LEFT);
            } else {
                return Directions(Direction.DOWN_RIGHT);
            }
        }
    }

    function makeMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure) internal {
        // remove all en passant flags
        setFlag(gameId, Flag.WHITE_EN_PASSANT, -1);
        setFlag(gameId, Flag.WHITE_EN_PASSANT, -1);

        // <---- Special Move ---->

        // Black King
        if (fromFigure == Pieces(Piece.BLACK_KING)) {
            // Update position flag
            setFlag(gameId, Flag.BLACK_KING_POS, int8(toIndex));
            // Castling
            if (fromIndex == 4 && toIndex == 2) {
                games[gameId].state[0] = 0;
                games[gameId].state[3] = Pieces(Piece.BLACK_ROOK);
            }
            if (fromIndex == 4 && toIndex == 6) {
                games[gameId].state[7] = 0;
                games[gameId].state[5] = Pieces(Piece.BLACK_ROOK);
            }

        }
        // White King
        if (fromFigure == Pieces(Piece.WHITE_KING)) {
            // Update position flag
            setFlag(gameId, Flag.WHITE_KING_POS, int8(toIndex));
            // Castling
            if (fromIndex == 116 && toIndex == 114) {
                games[gameId].state[112] = 0;
                games[gameId].state[115] = Pieces(Piece.BLACK_ROOK);
            }
            if (fromIndex == 116 && toIndex == 118) {
                games[gameId].state[119] = 0;
                games[gameId].state[117] = Pieces(Piece.BLACK_ROOK);
            }

        }

        // Remove Castling Flag if king or Rook moves. But only at the first move for better performance

        // Black
        if (fromFigure == Pieces(Piece.BLACK_KING)) {
            if (fromIndex == 4) {
                setFlag(gameId, Flag.BLACK_LEFT_CASTLING, -1);
                setFlag(gameId, Flag.BLACK_RIGHT_CASTLING, -1);
            }
        }
        if (fromFigure == Pieces(Piece.BLACK_ROOK)) {
            if (fromIndex == 0) {
                setFlag(gameId, Flag.BLACK_LEFT_CASTLING, -1);
            }
            if (fromIndex == 7) {
                setFlag(gameId, Flag.BLACK_RIGHT_CASTLING, -1);
            }
        }

        // White
        if (fromFigure == Pieces(Piece.WHITE_KING)) {
            if (fromIndex == 116) {
                setFlag(gameId, Flag.WHITE_LEFT_CASTLING, -1);
                setFlag(gameId, Flag.WHITE_RIGHT_CASTLING, -1);
            }
        }
        if (fromFigure == Pieces(Piece.WHITE_ROOK)) {
            if (fromIndex == 112) {
                setFlag(gameId, Flag.WHITE_LEFT_CASTLING, -1);
            }
            if (fromIndex == 119) {
                setFlag(gameId, Flag.WHITE_RIGHT_CASTLING, -1);
            }
        }

        int8 direction = getDirection(fromIndex, toIndex);

        // PAWN - EN PASSANT or DOUBLE STEP
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_PAWN))) {
            // En Passant - remove caught pawn
            // en passant if figure: pawn and diagonal move to empty field
            if (is_diagonal(direction) && toFigure == Pieces(Piece.EMPTY)) {
                if (fromFigure == Pieces(Piece.BLACK_PAWN)) {
                    games[gameId].state[uint(int(toIndex) + Directions(Direction.UP))] = 0;
                } else {
                    games[gameId].state[uint(int(toIndex) + Directions(Direction.DOWN))] = 0;
                }
            }

            // in case of double Step: set EN_PASSANT-Flag
            else if (int(fromIndex) + direction + direction == int(toIndex)) {
                if (fromFigure == Pieces(Piece.BLACK_PAWN)) {
                    setFlag(gameId, Flag.BLACK_EN_PASSANT, int8(toIndex) + Directions(Direction.UP));
                } else {
                    setFlag(gameId, Flag.WHITE_EN_PASSANT, int8(toIndex) + Directions(Direction.DOWN));
                }
            }
        }

        // <---- Promotion --->

        int targetRank = int(toIndex/16);
        if (targetRank == 7 && fromFigure == Pieces(Piece.BLACK_PAWN)) {
            games[gameId].state[toIndex] = Pieces(Piece.BLACK_QUEEN);
        }
        else if (targetRank == 0 && fromFigure == Pieces(Piece.WHITE_PAWN)) {
            games[gameId].state[toIndex] = Pieces(Piece.WHITE_QUEEN);
        }
        else {
            // Normal move
            games[gameId].state[toIndex] = games[gameId].state[fromIndex];
        }

        games[gameId].state[fromIndex] = 0;
    }

    // checks whether movingPlayerColor's king gets checked by move
    function checkLegality(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 movingPlayerColor) internal returns (bool){
        // the king already gets tested when he moves
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_KING)))
            return;

        // through move of fromFigure from fromIndex king may now be in danger from that direction
        // get that direction
        int8 kingIndex = getOwnKing(gameId, movingPlayerColor);
        int8 kingDangerDirection = getDirection(uint256(kingIndex), fromIndex);

        // get the first Figure in this direction. Threat of Knight does not change through move of fromFigure.
        // All other figures can not jump over other figures. So only the first figure matters.
        int8 firstFigureIndex = getFirstFigure(gameId, kingDangerDirection,kingIndex);

        // if we found a figure in the danger direction
        if (firstFigureIndex != -1) {
            int8 firstFigure = games[gameId].state[uint(firstFigureIndex)];

            // if its an enemy
            if (firstFigure * movingPlayerColor > 0) {
                // check if the figure can move to the field of the king
                int8 kingFigure = Pieces(Piece.BLACK_KING)* movingPlayerColor;
                if (validateMove(gameId, uint256(firstFigureIndex), uint256(kingIndex), firstFigure, kingFigure, movingPlayerColor)) {
                    // it can
                    throw;
                }
            }

        }

        return;
    }

    function testIfCheck() {

    }

    function surrender(bytes32 gameId) public {
        if (games[gameId].winner != 0) {
            // Game already ended
            throw;
        }
        if (games[gameId].player1 == msg.sender) {
            // Player 1 surrendered, player 2 won
            games[gameId].winner = games[gameId].player2;
        } else if(games[gameId].player2 == msg.sender) {
            // Player 2 surrendered, player 1 won
            games[gameId].winner = games[gameId].player1;
        } else {
            // Sender is not a participant of this game
            throw;
        }

        GameEnded(gameId, games[gameId].winner);
    }

    // gets the first figure in direction from start, not including start
    function getFirstFigure(bytes32 gameId, int8 direction, int8 start) returns (int8){
        int currentIndex = start + direction;

        // as long as we do not reach the end of the board walk in direction
        while(currentIndex & 0x88 == 0){

            // if there is a figure at current field return it
            if(games[gameId].state[uint(currentIndex)] != Pieces(Piece.EMPTY))
                return int8(currentIndex);

            //otherwise move to the next field in that direction
            currentIndex = currentIndex + direction;
        }

        return -1;
    }

    function getGameId(address player, int index) constant returns (bytes32) {
        return gamesOfPlayers[player][index];
    }

    /*------------------------HELPER FUNCTIONS------------------------*/

    // This returns the absolute value of an integer
    function abs(int256 value) returns (uint256){
        if (value>=0) return uint256(value);
        else return uint256(-1*value);
    }

    function is_diagonal(int8 direction) internal returns (bool){
      return !(abs(direction) == 16 || abs(direction) == 1);
    }

    function getOwnKing(bytes32 gameId, int8 movingPlayerColor) returns (int8){
        if(movingPlayerColor == Players(Player.WHITE))
            return getFlag(gameId, Flag.BLACK_KING_POS);
        else
            return getFlag(gameId, Flag.WHITE_KING_POS);
    }

    /* This unnamed function is called whenever someone tries to send ether to it */
    function () {
        throw;     // Prevents accidental sending of ether
    }
}

/**
 * Chess contract
 * Stores any amount of games with two players and current state.
 * State encoding:
 *    positive numbers for white, negative numbers for black
 *    for details, see
 *    https://github.com/ise-ethereum/on-chain-chess/wiki/Chess-board-representation
 */

 contract Chess {
    bytes constant defaultState = '\x04\x06\x05\x03\x02\x05\x06\x04\x08\x08\x08\x0c\x08\x08\x08\x08\x07\x07\x07\x07\x07\x07\x07\x07\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x09\x09\x09\x09\x09\x09\x09\x09\x08\x08\x08\x08\x08\x08\x08\x08\x0c\x0a\x0b\x0d\x0e\x0b\x0a\x0c\x08\x08\x08\x7c\x08\x08\x08\x08';

    bool debug; // If contract is deployed in debug mode, some debug features are enabled

    modifier debugOnly {
        if (!debug)
            throw;
        _
    }

    struct Game {
        address player1;
        address player2;
        string player1Alias;
        string player2Alias;
        address nextPlayer;
        address playerWhite; // Player that is white in this game
        address winner;
        uint value; // What this game is worth ether paid into the game

        int8[128] state;
    }

    mapping (bytes32 => Game) public games;
    mapping (address => mapping (int => bytes32)) public gamesOfPlayers;
    mapping (address => int) public numberGamesOfPlayers;

    // stack of open game ids
    mapping (bytes32 => bytes32) public openGameIds;
    bytes32 public head;

    /* Flags needed for validation
     * Usage e.g. Flags(Flag.FLAG_NAME)
     * Directions(Direction.UP)
     */
    enum Player { WHITE, BLACK }
    enum Direction { UP, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT }
    bytes constant c_Directions = "\x30\x31\x41\x51\x50\x4f\x3f\x2f";
    enum Piece { BLACK_KING, BLACK_QUEEN, BLACK_ROOK, BLACK_BISHOP, BLACK_KNIGHT, BLACK_PAWN, EMPTY, WHITE_PAWN, WHITE_KNIGHT, WHITE_BISHOP, WHITE_ROOK, WHITE_QUEEN, WHITE_KING }
    enum Flag { WHITE_KING_POS, BLACK_KING_POS, CURRENT_PLAYER, WHITE_LEFT_CASTLING, WHITE_RIGHT_CASTLING, BLACK_LEFT_CASTLING, BLACK_RIGHT_CASTLING, BLACK_EN_PASSANT, WHITE_EN_PASSANT}
    bytes constant c_Flags = "\x7b\x0b\x38\x4e\x4f\x3e\x3f\x3d\x4d\x3c\x4c";
    function Flags(Flag i) constant internal returns (uint) {
       return uint(c_Flags[uint(i)]);
    }
    function Pieces(Piece i) constant internal returns (int8) {
        return -6 + int8(uint(i));
    }
    function Directions(Direction i) constant internal returns (int8) {
        return -64 + int8(c_Directions[uint(i)]);
    }
    function Players(Player p) constant internal returns (int8) {
        if (p == Player.WHITE) {
            return 1;
        }
        return -1;
    }

    bytes constant knightMoves = '\x1f\x21\x2e\x32\x4e\x52\x5f\x61';

    function Chess(bool enableDebugging) {
        debug = enableDebugging;
        head = 'end';
    }

    event GameInitialized(bytes32 indexed gameId, address indexed player1, string player1Alias, address playerWhite);
    event GameJoined(bytes32 indexed gameId, address indexed player1, string player1Alias, address indexed player2, string player2Alias, address playerWhite);

    event GameStateChanged(bytes32 indexed gameId, int8[128] state);
    event Move(bytes32 indexed gameId, address indexed player, uint256 fromIndex, uint256 toIndex);
    event GameEnded(bytes32 indexed gameId, address indexed winner);

    event DebugInts(string message, int value1, int value2, int value3);

    /**
     * Convenience function to set a flag
     * Usage: setFlag(gameId, Flag.BLACK_KING_POS, 4);
     */

    function setFlag(bytes32 gameId, Flag flag, int value) internal {
        games[gameId].state[Flags(flag)] = int8(value);
    }

    /**
     * Convenience function to set a flag
     * Usage: getFlag(gameId, Flag.BLACK_KING_POS);
     */
    function getFlag(bytes32 gameId, Flag flag) internal returns (int8) {
        return games[gameId].state[Flags(flag)];

    }

    /**
     * Initialize a new game
     * string player1Alias: Alias of the player creating the game
     * bool playAsWhite: Pass true or false depending on if the creator will play as white
     */
    function initGame(string player1Alias, bool playAsWhite) public {
        // Generate game id based on player's addresses and current block number
        bytes32 gameId = sha3(msg.sender, block.number);

        // Initialize participants
        games[gameId].player1 = msg.sender;
        games[gameId].player1Alias = player1Alias;

        // Initialize game value
        games[gameId].value = msg.value;
        // Initialize state

        for (uint i = 0; i < 128; i++) {
            // Read defaultState bytes string, which is offset by 8 to be > 0
            games[gameId].state[i] = int8(defaultState[i]) - 8;
        }

        if (playAsWhite) {
            // Player 1 will play as white
            games[gameId].playerWhite = msg.sender;

            // Game starts with White, so here player 1
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Add game to gamesOfPlayers
        gamesOfPlayers[msg.sender][numberGamesOfPlayers[msg.sender]] = gameId;
        numberGamesOfPlayers[msg.sender]++;

        // Add to openGameIds
        openGameIds[gameId] = head;
        head = gameId;

        // Sent notification events
        GameInitialized(gameId, games[gameId].player1, player1Alias, games[gameId].playerWhite);
        GameStateChanged(gameId, games[gameId].state);
    }

    /**
     * Join an initialized game
     * bytes32 gameId: ID of the game to join
     * string player2Alias: Alias of the player that is joining
     */
    function joinGame(bytes32 gameId, string player2Alias) public {

        // Check that this game does not have a second player yet
        if (games[gameId].player2 != 0) {
            throw;
        }

        games[gameId].player2 = msg.sender;
        games[gameId].player2Alias = player2Alias;

        // If the other player isn't white, player2 will play as white
        if (games[gameId].playerWhite == 0) {
            games[gameId].playerWhite = msg.sender;
            // Game starts with White, so here player2
            games[gameId].nextPlayer = games[gameId].player2;
        }

        // Add game to gamesOfPlayers
        gamesOfPlayers[msg.sender][numberGamesOfPlayers[msg.sender]] = gameId;
        numberGamesOfPlayers[msg.sender]++;

        // Remove from openGameIds
        if (head == gameId) {
            head = openGameIds[head];

            openGameIds[gameId] = 0;
        } else {
            for (var g = head; g != 'end' && openGameIds[g] != 'end'; g = openGameIds[g]) {
                if (openGameIds[g] == gameId) {
                    openGameIds[g] = openGameIds[gameId];
                    openGameIds[gameId] = 0;
                    break;
                }
            }
        }

        GameJoined(gameId, games[gameId].player1, games[gameId].player1Alias, games[gameId].player2, player2Alias, games[gameId].playerWhite);
    }

    /* Explicity set game state. Only in debug mode */
    function setGameState(bytes32 gameId, int8[128] state, address nextPlayer) debugOnly public {
        games[gameId].state = state;
        games[gameId].nextPlayer = nextPlayer;
        GameStateChanged(gameId, games[gameId].state);
    }

    /**
    * Allows the winner of a game to claim their ether
    * bytes32 gameId: ID of the game they have won
    */
    function claimWin(bytes32 gameId) public {

    }

    /* validates a move and executes it */
    function move(bytes32 gameId, uint256 fromIndex, uint256 toIndex) public {
        // Check that it is this player's turn
        if (games[gameId].nextPlayer != msg.sender) {
            throw;
        }

        int8 currentPlayerColor;
        if (msg.sender == games[gameId].playerWhite) {
            currentPlayerColor = Players(Player.WHITE);
        } else {
            currentPlayerColor = Players(Player.BLACK);
        }

        int8 fromFigure = games[gameId].state[fromIndex];
        int8 toFigure = games[gameId].state[toIndex];

        // Simple sanity checks
        sanityCheck(fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

        // Check if move is technically possible
        if (!validateMove(gameId, fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor)) {
            throw;
        }

        // For all pieces except knight, check if way is free
        if (abs(fromFigure) != uint(Pieces(Piece.WHITE_KNIGHT))) {
            // In case of king, it will check that he is not in check on any of the fields he moves over
            bool checkForCheck = abs(fromFigure) == uint(Pieces(Piece.WHITE_KING));
            checkWayFree(gameId, fromIndex, toIndex, currentPlayerColor, checkForCheck);
        }

        // Make the move
        makeMove(gameId, fromIndex, toIndex, fromFigure, toFigure);

        // Check legality (player's own king may not be in check after move)
        checkLegality(gameId, fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

        // Set nextPlayer
        if (msg.sender == games[gameId].player1) {
            games[gameId].nextPlayer = games[gameId].player2;
        } else {
            games[gameId].nextPlayer = games[gameId].player1;
        }

        // Send events
        Move(gameId, msg.sender, fromIndex, toIndex);
        GameStateChanged(gameId, games[gameId].state);
    }

    function sanityCheck(uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 currentPlayerColor) internal {
        // check that move is within the field
        if (toIndex & 0x88 != 0 || fromIndex & 0x88 != 0) {
            throw;
        }

        // check that from and to are distinct
        if (fromIndex == toIndex) {
            throw;
        }

        // check if the toIndex is empty (= is 0) or contains an enemy figure ("positive" * "negative" = "negative")
        // --> this only allows captures (negative results)  or moves to empty fields ( = 0)
        if (fromFigure * toFigure > 0) {
            throw;
        }

        // check if mover of the figure is the owner of the figure
        // also check if there is a figure at fromIndex to move (fromFigure != 0)
        if (currentPlayerColor * fromFigure <= 0) {
            throw;
        }
    }

    /**
     * Validates if a move is technically (not legally) possible,
     * i.e. if piece is capable to move this way
     */
    function validateMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 movingPlayerColor) returns (bool) {
        int8 direction = getDirection(fromIndex, toIndex);
        bool isDiagonal = !(abs(direction) == 16 || abs(direction) == 1);

        if (debug) {
            DebugInts('validateMove. fromFigure, toFigure, direction', int(fromFigure), int(fromFigure), int(direction));
        }

        // Kings
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_KING))) {
            // Normal move
            if (int(fromIndex) + direction == int(toIndex)) {
                return true;
            }
            // Castling
            if (checkForCheck(gameId, fromIndex, movingPlayerColor)) {
                // Cannot move if already in check
                return false;
            }
            if (fromFigure == Pieces(Piece.BLACK_KING)) {
                if (4 == fromIndex && toFigure == 0) {
                    if (toIndex == 2 && getFlag(gameId, Flag.BLACK_LEFT_CASTLING) >= 0) {
                        return true;
                    }
                    if (toIndex == 6 && getFlag(gameId, Flag.BLACK_RIGHT_CASTLING) >= 0) {
                        return true;
                    }
                }
            }
            if (fromFigure == Pieces(Piece.WHITE_KING)) {
                if (116 == fromIndex && toFigure == 0) {
                    if (toIndex == 114 && getFlag(gameId, Flag.WHITE_LEFT_CASTLING) >= 0) {
                        return true;
                    }
                    if (toIndex == 118 && getFlag(gameId, Flag.WHITE_RIGHT_CASTLING) >= 0) {
                        return true;
                    }
                }
            }

            return false;
        }

        // Bishops, Queens, Rooks
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_BISHOP)) ||
            abs(fromFigure) == uint(Pieces(Piece.WHITE_QUEEN)) ||
            abs(fromFigure) == uint(Pieces(Piece.WHITE_ROOK))) {

            // Bishop can only walk diagonally, Rook only non-diagonally
            if (!isDiagonal && abs(fromFigure) == uint(Pieces(Piece.WHITE_BISHOP)) ||
                isDiagonal && abs(fromFigure) == uint(Pieces(Piece.WHITE_ROOK))) {
                return false;
            }

            // Traverse all fields in direction
            int temp = int(fromIndex);
            // walk in direction while inside board to find toIndex
            while (temp & 0x88 == 0) {
                if (uint(temp) == toIndex) {
                    return true;
                }
                temp += direction;
            }

            return false;
        }

        // Pawns
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_PAWN))) {
            // Black can only move in positive, White negative direction
            if (fromFigure == Pieces(Piece.BLACK_PAWN) && direction < 0 ||
                fromFigure == Pieces(Piece.WHITE_PAWN) && direction > 0) {
                return false;
            }
            // Forward move
            if (!isDiagonal) {
                // no horizontal movement allowed
                if (abs(direction) < 2) {
                    return false;
                }
                // simple move
                if (int(fromIndex) + direction == int(toIndex)) {
                    if(toFigure == Pieces(Piece.EMPTY)){
                        return true;
                    }

                }
                // double move
                if (int(fromIndex) + direction + direction == int(toIndex)) {
                    // Can only do double move starting form specific ranks
                    int rank = int(fromIndex/16);
                    if (1 == rank || 6 == rank) {
                        if(toFigure == Pieces(Piece.EMPTY)){
                            return true;
                        }
                    }
                }
                return false;
            }
            // diagonal move
            if (int(fromIndex) + direction == int(toIndex)) {
                // if empty, the en passant flag needs to be set
                if (toFigure * fromFigure == 0) {
                    if (fromFigure == Pieces(Piece.BLACK_PAWN) &&
                        getFlag(gameId, Flag.WHITE_EN_PASSANT) == int(toIndex) ||
                        fromFigure == Pieces(Piece.WHITE_PAWN) &&
                        getFlag(gameId, Flag.BLACK_EN_PASSANT) == int(toIndex)) {
                        return true;
                    }
                    return false;
                }
                // If not empty
                return true;
            }

            return false;
        }

        // Knights
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_KNIGHT))) {
            for (uint i; i < 8; i++) {
                if (int(fromIndex) + int(knightMoves[i]) - 64 == int(toIndex)) {
                    return true;
                }
            }
            return false;
        }

        return false;

    }

    /**
     * Checks if the way between fromIndex and toIndex is unblocked
     */
    function checkWayFree(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 currentPlayerColor, bool shouldCheckForCheck) internal {
        int8 direction = getDirection(fromIndex, toIndex);
        int currentIndex = int(fromIndex) + direction;

        // as long as we do not reach the desired position walk in direction and check
        while (int(toIndex) != currentIndex) {
            // we reached the end of the field
            if (currentIndex & 0x88 != 0) {
                throw;
            }
            // the path is blocked
            if (games[gameId].state[uint(currentIndex)] != 0) {
                throw;
            }
            // Check for check in case of king
            if (shouldCheckForCheck && checkForCheck(gameId, uint(currentIndex), currentPlayerColor)) {
                throw;
            }
            currentIndex = currentIndex + direction;
        }
        return;
    }

    function checkForCheck(bytes32 gameId, uint256 kingIndex, int8 currentPlayerColor) internal returns (bool) {

        //get Position of King
       // int8 kingIndex = getOwnKing(gameId, currentPlayerColor);

        // look in every direction whether there is an enemy figure that checks the king
        for(uint dir = 0; dir < 8; dir ++){
          // get the first Figure in this direction. Threat of Knight does not change through move of fromFigure.
          // All other figures can not jump over figures. So only the first figure matters.
          int8 firstFigureIndex = getFirstFigure(gameId, Directions(Direction(dir)),int8(kingIndex));

          // if we found a figure in the danger direction
          if (firstFigureIndex != -1) {
              int8 firstFigure = games[gameId].state[uint(firstFigureIndex)];

              // if its an enemy
              if (firstFigure * currentPlayerColor > 0) {
                  // check if the enemy figure can move to the field of the king
                  int8 kingFigure = Pieces(Piece.BLACK_KING)* currentPlayerColor;
                  if (validateMove(gameId, uint256(firstFigureIndex), uint256(kingIndex), firstFigure, kingFigure, currentPlayerColor)) {
                      // it can
                      return true; // king is checked
                  }
              }

          }
        }

        //Knights
        // Knights can jump over figures. So they need to be tested seperately with every possible move.
        for(uint move = 0; move < 8; move ++){
            // currentMoveIndex: where knight could start with move that checks king
            int8 currentMoveIndex = int8(kingIndex) + int8(knightMoves[move]);

            // if inside the board
            if(uint(currentMoveIndex) & 0x88 == 0){

                // get Figure at currentMoveIndex
                int8 currentFigure = Pieces(Piece(currentMoveIndex));

                // if it is an enemy knight, king can be checked
                if(currentFigure * currentPlayerColor == Pieces(Piece.WHITE_KNIGHT)){
                    return true; // king is checked
                }
            }
        }

        return false; // king is not checked
    }

    function getDirection(uint256 fromIndex, uint256 toIndex) constant internal returns (int8) {
        // check if the figure is moved up or left of its origin
        bool isAboveLeft = fromIndex > toIndex;

        // check if the figure is moved in an horizontal plane
        // this code works because there is an eight square difference between the horizontal panes (the offboard)
        bool isSameHorizontal = (abs(int256(fromIndex) - int256(toIndex)) < (8));

        // check if the figure is moved in a vertical line
        bool isSameVertical = (fromIndex%8 == toIndex%8);

        // check if the figure is moved to the left of its origin
        bool isLeftSide = (fromIndex%8 > toIndex%8);

        /*Check directions*/
        if (isAboveLeft) {
            if (isSameVertical) {
                return Directions(Direction.UP);
            }
            if (isSameHorizontal) {
                return Directions(Direction.LEFT);
            }
            if (isLeftSide) {
                return Directions(Direction.UP_LEFT);
            } else {
                return Directions(Direction.UP_RIGHT);
            }
        } else {
            if (isSameVertical) {
                return Directions(Direction.DOWN);
            }
            if (isSameHorizontal) {
                return Directions(Direction.RIGHT);
            }
            if (isLeftSide) {
                return Directions(Direction.DOWN_LEFT);
            } else {
                return Directions(Direction.DOWN_RIGHT);
            }
        }
    }

    function makeMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure) internal {
        // remove all en passant flags
        setFlag(gameId, Flag.WHITE_EN_PASSANT, -1);
        setFlag(gameId, Flag.WHITE_EN_PASSANT, -1);

        // <---- Special Move ---->

        // Black King
        if (fromFigure == Pieces(Piece.BLACK_KING)) {
            // Update position flag
            setFlag(gameId, Flag.BLACK_KING_POS, int8(toIndex));
            // Castling
            if (fromIndex == 4 && toIndex == 2) {
                games[gameId].state[0] = 0;
                games[gameId].state[3] = Pieces(Piece.BLACK_ROOK);
            }
            if (fromIndex == 4 && toIndex == 6) {
                games[gameId].state[7] = 0;
                games[gameId].state[5] = Pieces(Piece.BLACK_ROOK);
            }

        }
        // White King
        if (fromFigure == Pieces(Piece.WHITE_KING)) {
            // Update position flag
            setFlag(gameId, Flag.WHITE_KING_POS, int8(toIndex));
            // Castling
            if (fromIndex == 116 && toIndex == 114) {
                games[gameId].state[112] = 0;
                games[gameId].state[115] = Pieces(Piece.BLACK_ROOK);
            }
            if (fromIndex == 116 && toIndex == 118) {
                games[gameId].state[119] = 0;
                games[gameId].state[117] = Pieces(Piece.BLACK_ROOK);
            }

        }

        // Remove Castling Flag if king or Rook moves. But only at the first move for better performance

        // Black
        if (fromFigure == Pieces(Piece.BLACK_KING)) {
            if (fromIndex == 4) {
                setFlag(gameId, Flag.BLACK_LEFT_CASTLING, -1);
                setFlag(gameId, Flag.BLACK_RIGHT_CASTLING, -1);
            }
        }
        if (fromFigure == Pieces(Piece.BLACK_ROOK)) {
            if (fromIndex == 0) {
                setFlag(gameId, Flag.BLACK_LEFT_CASTLING, -1);
            }
            if (fromIndex == 7) {
                setFlag(gameId, Flag.BLACK_RIGHT_CASTLING, -1);
            }
        }

        // White
        if (fromFigure == Pieces(Piece.WHITE_KING)) {
            if (fromIndex == 116) {
                setFlag(gameId, Flag.WHITE_LEFT_CASTLING, -1);
                setFlag(gameId, Flag.WHITE_RIGHT_CASTLING, -1);
            }
        }
        if (fromFigure == Pieces(Piece.WHITE_ROOK)) {
            if (fromIndex == 112) {
                setFlag(gameId, Flag.WHITE_LEFT_CASTLING, -1);
            }
            if (fromIndex == 119) {
                setFlag(gameId, Flag.WHITE_RIGHT_CASTLING, -1);
            }
        }

        int8 direction = getDirection(fromIndex, toIndex);

        // PAWN - EN PASSANT or DOUBLE STEP
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_PAWN))) {
            // En Passant - remove caught pawn
            // en passant if figure: pawn and diagonal move to empty field
            if (is_diagonal(direction) && toFigure == Pieces(Piece.EMPTY)) {
                if (fromFigure == Pieces(Piece.BLACK_PAWN)) {
                    games[gameId].state[uint(int(toIndex) + Directions(Direction.UP))] = 0;
                } else {
                    games[gameId].state[uint(int(toIndex) + Directions(Direction.DOWN))] = 0;
                }
            }

            // in case of double Step: set EN_PASSANT-Flag
            else if (int(fromIndex) + direction + direction == int(toIndex)) {
                if (fromFigure == Pieces(Piece.BLACK_PAWN)) {
                    setFlag(gameId, Flag.BLACK_EN_PASSANT, int8(toIndex) + Directions(Direction.UP));
                } else {
                    setFlag(gameId, Flag.WHITE_EN_PASSANT, int8(toIndex) + Directions(Direction.DOWN));
                }
            }
        }

        // <---- Promotion --->

        int targetRank = int(toIndex/16);
        if (targetRank == 7 && fromFigure == Pieces(Piece.BLACK_PAWN)) {
            games[gameId].state[toIndex] = Pieces(Piece.BLACK_QUEEN);
        }
        else if (targetRank == 0 && fromFigure == Pieces(Piece.WHITE_PAWN)) {
            games[gameId].state[toIndex] = Pieces(Piece.WHITE_QUEEN);
        }
        else {
            // Normal move
            games[gameId].state[toIndex] = games[gameId].state[fromIndex];
        }

        games[gameId].state[fromIndex] = 0;
    }

    // checks whether movingPlayerColor's king gets checked by move
    function checkLegality(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 movingPlayerColor) internal returns (bool){
        // the king already gets tested when he moves
        if (abs(fromFigure) == uint(Pieces(Piece.WHITE_KING)))
            return;

        // through move of fromFigure from fromIndex king may now be in danger from that direction
        // get that direction
        int8 kingIndex = getOwnKing(gameId, movingPlayerColor);
        int8 kingDangerDirection = getDirection(uint256(kingIndex), fromIndex);

        // get the first Figure in this direction. Threat of Knight does not change through move of fromFigure.
        // All other figures can not jump over other figures. So only the first figure matters.
        int8 firstFigureIndex = getFirstFigure(gameId, kingDangerDirection,kingIndex);

        // if we found a figure in the danger direction
        if (firstFigureIndex != -1) {
            int8 firstFigure = games[gameId].state[uint(firstFigureIndex)];

            // if its an enemy
            if (firstFigure * movingPlayerColor > 0) {
                // check if the figure can move to the field of the king
                int8 kingFigure = Pieces(Piece.BLACK_KING)* movingPlayerColor;
                if (validateMove(gameId, uint256(firstFigureIndex), uint256(kingIndex), firstFigure, kingFigure, movingPlayerColor)) {
                    // it can
                    throw;
                }
            }

        }

        return;
    }

    function testIfCheck() {

    }

    function surrender(bytes32 gameId) public {
        if (games[gameId].winner != 0) {
            // Game already ended
            throw;
        }
        if (games[gameId].player1 == msg.sender) {
            // Player 1 surrendered, player 2 won
            games[gameId].winner = games[gameId].player2;
        } else if(games[gameId].player2 == msg.sender) {
            // Player 2 surrendered, player 1 won
            games[gameId].winner = games[gameId].player1;
        } else {
            // Sender is not a participant of this game
            throw;
        }

        GameEnded(gameId, games[gameId].winner);
    }

    // gets the first figure in direction from start, not including start
    function getFirstFigure(bytes32 gameId, int8 direction, int8 start) returns (int8){
        int currentIndex = start + direction;

        // as long as we do not reach the end of the board walk in direction
        while(currentIndex & 0x88 == 0){

            // if there is a figure at current field return it
            if(games[gameId].state[uint(currentIndex)] != Pieces(Piece.EMPTY))
                return int8(currentIndex);

            //otherwise move to the next field in that direction
            currentIndex = currentIndex + direction;
        }

        return -1;
    }

    function getGameId(address player, int index) constant returns (bytes32) {
        return gamesOfPlayers[player][index];
    }

    /*------------------------HELPER FUNCTIONS------------------------*/

    // This returns the absolute value of an integer
    function abs(int256 value) returns (uint256){
        if (value>=0) return uint256(value);
        else return uint256(-1*value);
    }

    function is_diagonal(int8 direction) internal returns (bool){
      return !(abs(direction) == 16 || abs(direction) == 1);
    }

    function getOwnKing(bytes32 gameId, int8 movingPlayerColor) returns (int8){
        if(movingPlayerColor == Players(Player.WHITE))
            return getFlag(gameId, Flag.BLACK_KING_POS);
        else
            return getFlag(gameId, Flag.WHITE_KING_POS);
    }

    /* This unnamed function is called whenever someone tries to send ether to it */
    function () {
        throw;     // Prevents accidental sending of ether
    }
}