removed unneded comments, removed erc zero, added ether zero

pragma solidity ^0.5.0;

import '../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol';

/**
* Health Decentralized Record Service (DRS)
* This contract enables creation of services and keys which can
* be managed, shared, traded, and sold using Health Cash (HLTH).
*
* These keys enable gatekeeper services and
* cryptographically secure data exchanges.
*/

contract HealthDRS is Ownable {

   address public latestContract = address(this);
   uint8 public version = 1;
   mapping (address => uint) pendingWithdrawals;

   struct Service {
       string url;
       address payable owner;
   }

   struct Key {
       address payable owner;
       bool canShare;
       bool canTrade;
       bool canSell;
       bytes32 service;
   }

   struct SalesOffer {
       address payable buyer;
       uint price;
       bool canSell;
   }

   mapping (bytes32 => Service) public services;
   bytes32[] public serviceList;

   mapping(bytes32 => Key) keys;
   bytes32[] public keyList;

   mapping(bytes32 => address[]) public owners;
   mapping(bytes32 => bytes32) public keyData;
   mapping(bytes32 => SalesOffer) public salesOffers;
   mapping(bytes32 => bytes32) public tradeOffers;

   event ServiceCreated(address indexed _owner, bytes32 indexed _service);
   event KeyCreated(address indexed _owner, bytes32 indexed _key);
   event KeySold(bytes32 _key, address indexed _seller, address indexed _buyer, uint _price);
   event KeysTraded(bytes32 indexed _key1, bytes32 indexed _key2);
   event Access(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _data);
   event Message(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _category, string _data);
   event Log(address indexed _owner, bytes32 indexed _from, uint _time, string _data);

   modifier validKey(bytes32 key) {
     require(keys[key].owner != address(0), "validKey() error");
     _;
   }

   modifier validService(bytes32 service) {
     require(services[service].owner != address(0), "validService() error");
     _;
   }

   modifier ownsKey(bytes32 key) {
       require(isKeyOwner(key, msg.sender), "ownsKey() error");
       _;
   }
   modifier ownsService(bytes32 service) {
       require(isServiceOwner(service, msg.sender), "ownsService() error");
       _;
   }

   modifier canSell(bytes32 key) {
     require(keys[key].canSell, "canSell() key can't be sold error");
     require(owners[key].length == 0, "canSell() key does not exist error");
     _;
   }

   modifier canTrade(bytes32 key) {
     require(keys[key].canTrade, "canTrade() keys[key].canTrade error");
     require(owners[key].length == 0, "canTrade() owners[key].length error");
     _;
   }

   modifier canShare(bytes32 key) {
     require(keys[key].canShare, "canShare() error");
     _;
   }

   //prevent accidentally sending/trapping ether
   function() external {
       revert("function() line 104 error");
   }

   //function - retrieve ether that was sent via coinbase/self destruct
   function zero() public onlyOwner {
     address payable _owner = address(uint160(this.owner()));
     _owner.transfer(address(this).balance);
   }

   function isKeyOwner(bytes32 key, address account)
       public
       view
       validKey(key)
       returns (bool)
   {
       if (keys[key].owner == account) {
           return true;
       } else {
           if (keys[key].canShare) {
               for (uint i = 0; i < owners[key].length; i++) {
                   if (owners[key][i] == account) {
                       return true;
                   }
               }
           }
       }
       return false;
   }

   function isServiceOwner(bytes32 service, address account)
       public
       view
       validService(service)
       returns (bool)
   {
       if (services[service].owner == account) {
           return true;
       } else {
           for (uint i = 0; i < owners[service].length; i++) {
               if (owners[service][i] == account) {
                   return true;
               }
          }
       }
       return false;
   }

   function getUrl(bytes32 service)
       public
       view
       validService(service)
       returns (string memory)
   {
      return services[service].url;
   }

   function getUrlFromKey(bytes32 key)
       public
       view
       validKey(key)
       returns (string memory)
   {
       return services[keys[key].service].url;
   }

   function updateUrl(bytes32 service, string memory url)
       public
       ownsService(service)
   {
      services[service].url = url;
   }

   function getOwnersLength(bytes32 key)
       public
       view
       returns (uint256)
    {
        return owners[key].length;
    }

   function setLatestContract(address _contract) public onlyOwner {
       latestContract = _contract;
   }

  /**
  * Create Services & Keys
  * Keys can also be issued to accounts
  */
   function createService(string memory url)
        public
   {
       bytes32 id = keccak256(abi.encode(msg.sender, url));
       require(services[id].owner == address(0), "createService() error"); //prevent overwriting
       services[id].owner = msg.sender;
       services[id].url = url;
       serviceList.push(id);
       emit ServiceCreated(msg.sender, id);
   }

   function createKey(bytes32 service)
       public
       ownsService(service)
   {
       issueKey(service, msg.sender);
   }

   function issueKey(bytes32 service, address payable issueTo)
       public
       ownsService(service)
   {
       bytes32 id = keccak256(abi.encode(service, issueTo, now));
       require(keys[id].owner == address(0), "issueKey() error");
       keys[id].owner = issueTo;
       keys[id].service = service;
       keyList.push(id);
       emit KeyCreated(issueTo, id);
   }

  /**
  * Share Services and Keys
  * allow owners to authorize other accounts
  * a service can disable sharing for their keys.
  * Can also unshare.
  */
   function shareKey(bytes32 key, address account)
       public
       ownsKey(key)
       canShare(key)
   {
       if (isKeyOwner(key, account) == false) {
           owners[key].push(account);
       }
   }

   function shareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       if (isServiceOwner(service, account) == false) {
           owners[service].push(account);
       }
   }

   function unshareKey(bytes32 key, address account)
       public
       ownsKey(key)
   {
       for (uint i = 0; i < owners[key].length; i++) {
           if (owners[key][i] == account) {
               if (i != owners[key].length - 1) {
                   owners[key][i] = owners[key][owners[key].length - 1];
               }
               owners[key].length--;
               break;
           }
       }
   }

   function unshareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       for (uint i = 0; i < owners[service].length; i++) {
           if (owners[service][i] == account) {
               if (i != owners[service].length - 1) {
                   owners[service][i] = owners[service][owners[service].length - 1];
               }
               owners[service].length--;
               break;
           }
       }
   }

   /**
   * Sell Keys
   * Services have to authorize keys for sale.
   * Key owners can disable key selling at time
   * of sale to prevent re-selling.
   */
   function createSalesOffer(bytes32 key, address payable buyer, uint price, bool _canSell)
       public
       ownsKey(key)
       canSell(key)
   {
       //cancel trade offer & create sales offer
       cancelTradeOffer(key);
       salesOffers[key].buyer = buyer;
       salesOffers[key].price = price;
       salesOffers[key].canSell = _canSell;
   }

   function cancelSalesOffer(bytes32 key)
       public
       ownsKey(key)
   {
       salesOffers[key].buyer = address(0);
       salesOffers[key].price = 0;
       salesOffers[key].canSell = false;
   }

   function purchaseKey(bytes32 key)
       public
       payable
       canSell(key)
   {

      require(salesOffers[key].price <= msg.value, "purchaseKey() salesOffers[key].price error");
      require(salesOffers[key].buyer == msg.sender, "purchaseKey() salesOffers[key].buyer error");

      uint balanceBeforeTransfer = keys[key].owner.balance;
      keys[key].owner.transfer(salesOffers[key].price);
      msg.sender.transfer(msg.value-salesOffers[key].price);
      assert(keys[key].owner.balance == balanceBeforeTransfer + salesOffers[key].price);

      emit KeySold(key, keys[key].owner, msg.sender, salesOffers[key].price);
      keys[key].owner = msg.sender;

      //set canSell - allows for non-resellable keys
      keys[key].canSell = salesOffers[key].canSell;

      //remove sales offer
      cancelSalesOffer(key);
   }

   /**
   * Trade keys
   * both keys have to be authorized
   * to trade by their respective services.
   */
    function createTradeOffer(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        //cancel sales offer & create a trade offer
        cancelSalesOffer(have);
        tradeOffers[have] = want;
    }

   function cancelTradeOffer(bytes32 key)
       public
       ownsKey(key)
   {
       tradeOffers[key] = bytes32(0); //remove the tradeOffer
   }

    function tradeKey(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        require(tradeOffers[want] == have, "tradeKey() error");

        emit KeysTraded(want, have);
        //complete the trade
        keys[have].owner = keys[want].owner;
        keys[want].owner = msg.sender;

        //remove trade offer
        cancelTradeOffer(want);
    }

   /**
   * Manage Keys
   * Service owner can set key permissions
   * disabling sharing, trading, or selling
   * removes shared owners, active trade
   * offers, and active sales offers respectively
   *
   * Should also be able to get a key and service,
   * get a count of keys and services, and get
   * a key and service key from the respective
   * lists.
   */
   //service owner can set permissions
   function setKeyPermissions(
       bytes32 key,
       bool canShare_,
       bool canTrade_,
       bool canSell_)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keys[key].canShare = canShare_;
       if (canShare_ == false) {
           owners[key].length = 0;
       }

       keys[key].canTrade = canTrade_;
       if (canTrade_ == false) {
           tradeOffers[key] = bytes32(0);
       }

       keys[key].canSell = canSell_;
       if (canSell_ == false) {
           salesOffers[key].buyer = address(0);
           salesOffers[key].price = 0;
           salesOffers[key].canSell = false;
       }

   }

   function getServiceCount() public view returns (uint) {
       return serviceList.length;
   }

   function getKeyCount() public view returns (uint) {
       return keyList.length;
   }

   function getService(bytes32 service)
       public
       view
       validService(service)
       returns(string memory, address)
   {
      return (services[service].url, services[service].owner);
   }

   function getKey(bytes32 key)
       public
       view
       validKey(key)
       returns(address, bool, bool, bool, bytes32)
   {
      return (keys[key].owner,
              keys[key].canShare,
              keys[key].canTrade,
              keys[key].canSell,
              keys[key].service);
   }

   /**
   * Key Data
   * A service can store public data for its keys.
   */
   function setKeyData(bytes32 key, bytes32 dataKey, bytes32 dataValue)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keyData[keccak256(abi.encodePacked(key,dataKey))] = dataValue;
   }

   function getKeyData(bytes32 key, bytes32 dataKey)
       public
       view
       validKey(key)
       returns (bytes32)
   {
       return keyData[keccak256(abi.encodePacked(key,dataKey))];
   }

   /**
   * ecrecover passthrough
   */
   function recoverAddress(
       bytes32 msgHash,
       uint8 v,
       bytes32 r,
       bytes32 s)
       public
       pure
       returns (address)
   {
     return ecrecover(msgHash, v, r, s);
   }

   /**
   * Logging & Messaging
   * functions for creating an auditable record of activity.
   * A service can log access from any of its keys.
   */
   function logAccess(bytes32 key, string memory data)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       emit Access(msg.sender, keys[key].service, key, now, data);
   }

   //services and keys can log messages to each other
   function message(bytes32 from, bytes32 to, string memory category, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
               isServiceOwner(from, msg.sender), "message() error 1");
       require(keys[to].owner != address(0) || services[to].owner != address(0), "message() error 2");

       emit Message(msg.sender, from, to, now, category, data);
   }

   //any key or service can log
   function log(bytes32 from, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
                isServiceOwner(from, msg.sender), "log() error");

       emit Log(msg.sender, from, now, data);
   }

}

pragma solidity ^0.5.0;

import '../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol';

/**
* Health Decentralized Record Service (DRS)
* This contract enables creation of services and keys which can
* be managed, shared, traded, and sold using Health Cash (HLTH).
*
* These keys enable gatekeeper services and
* cryptographically secure data exchanges.
*/

contract HealthDRS is Ownable {

   address public latestContract = address(this);
   uint8 public version = 1;
   mapping (address => uint) pendingWithdrawals;

   struct Service {
       string url;
       address payable owner;
   }

   struct Key {
       address payable owner;
       bool canShare;
       bool canTrade;
       bool canSell;
       bytes32 service;
   }

   struct SalesOffer {
       address payable buyer;
       uint price;
       bool canSell;
   }

   mapping (bytes32 => Service) public services;
   bytes32[] public serviceList;

   mapping(bytes32 => Key) keys;
   bytes32[] public keyList;

   mapping(bytes32 => address[]) public owners;
   mapping(bytes32 => bytes32) public keyData;
   mapping(bytes32 => SalesOffer) public salesOffers;
   mapping(bytes32 => bytes32) public tradeOffers;

   event ServiceCreated(address indexed _owner, bytes32 indexed _service);
   event KeyCreated(address indexed _owner, bytes32 indexed _key);
   event KeySold(bytes32 _key, address indexed _seller, address indexed _buyer, uint _price);
   event KeysTraded(bytes32 indexed _key1, bytes32 indexed _key2);
   event Access(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _data);
   event Message(address indexed _owner, bytes32 indexed _from, bytes32 indexed _to, uint _time, string _category, string _data);
   event Log(address indexed _owner, bytes32 indexed _from, uint _time, string _data);

   modifier validKey(bytes32 key) {
     require(keys[key].owner != address(0), "validKey() error");
     _;
   }

   modifier validService(bytes32 service) {
     require(services[service].owner != address(0), "validService() error");
     _;
   }

   modifier ownsKey(bytes32 key) {
       require(isKeyOwner(key, msg.sender), "ownsKey() error");
       _;
   }
   modifier ownsService(bytes32 service) {
       require(isServiceOwner(service, msg.sender), "ownsService() error");
       _;
   }

   modifier canSell(bytes32 key) {
     require(keys[key].canSell, "canSell() key can't be sold error");
     require(owners[key].length == 0, "canSell() key does not exist error");
     _;
   }

   modifier canTrade(bytes32 key) {
     require(keys[key].canTrade, "canTrade() keys[key].canTrade error");
     require(owners[key].length == 0, "canTrade() owners[key].length error");
     _;
   }

   modifier canShare(bytes32 key) {
     require(keys[key].canShare, "canShare() error");
     _;
   }

   //prevent accidentally sending/trapping ether
   function() external {
       revert("function() line 104 error");
   }

   function isKeyOwner(bytes32 key, address account)
       public
       view
       validKey(key)
       returns (bool)
   {
       if (keys[key].owner == account) {
           return true;
       } else {
           if (keys[key].canShare) {
               for (uint i = 0; i < owners[key].length; i++) {
                   if (owners[key][i] == account) {
                       return true;
                   }
               }
           }
       }
       return false;
   }

   function isServiceOwner(bytes32 service, address account)
       public
       view
       validService(service)
       returns (bool)
   {
       if (services[service].owner == account) {
           return true;
       } else {
           for (uint i = 0; i < owners[service].length; i++) {
               if (owners[service][i] == account) {
                   return true;
               }
          }
       }
       return false;
   }

   function getUrl(bytes32 service)
       public
       view
       validService(service)
       returns (string memory)
   {
      return services[service].url;
   }

   function getUrlFromKey(bytes32 key)
       public
       view
       validKey(key)
       returns (string memory)
   {
       return services[keys[key].service].url;
   }

   function updateUrl(bytes32 service, string memory url)
       public
       ownsService(service)
   {
      services[service].url = url;
   }

   function getOwnersLength(bytes32 key)
       public
       view
       returns (uint256)
    {
        return owners[key].length;
    }

    //allow owner access to tokens erroneously transferred to this contract
   /*function recoverTokens(address payable _token, uint amount) public onlyOwner {
       _token.transfer(amount);
   }*/

   function setLatestContract(address _contract) public onlyOwner {
       latestContract = _contract;
   }

  /**
  * Create Services & Keys
  * Keys can also be issued to accounts
  */
   function createService(string memory url)
        public
   {
       bytes32 id = keccak256(abi.encode(msg.sender, url));
       require(services[id].owner == address(0), "createService() error"); //prevent overwriting
       services[id].owner = msg.sender;
       services[id].url = url;
       serviceList.push(id);
       emit ServiceCreated(msg.sender, id);
   }

   function createKey(bytes32 service)
       public
       ownsService(service)
   {
       issueKey(service, msg.sender);
   }

   function issueKey(bytes32 service, address payable issueTo)
       public
       ownsService(service)
   {
       bytes32 id = keccak256(abi.encode(service, issueTo, now));
       require(keys[id].owner == address(0), "issueKey() error");
       keys[id].owner = issueTo;
       keys[id].service = service;
       keyList.push(id);
       emit KeyCreated(issueTo, id);
   }

  /**
  * Share Services and Keys
  * allow owners to authorize other accounts
  * a service can disable sharing for their keys.
  * Can also unshare.
  */
   function shareKey(bytes32 key, address account)
       public
       ownsKey(key)
       canShare(key)
   {
       if (isKeyOwner(key, account) == false) {
           owners[key].push(account);
       }
   }

   function shareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       if (isServiceOwner(service, account) == false) {
           owners[service].push(account);
       }
   }

   function unshareKey(bytes32 key, address account)
       public
       ownsKey(key)
   {
       for (uint i = 0; i < owners[key].length; i++) {
           if (owners[key][i] == account) {
               if (i != owners[key].length - 1) {
                   owners[key][i] = owners[key][owners[key].length - 1];
               }
               owners[key].length--;
               break;
           }
       }
   }

   function unshareService(bytes32 service, address account)
       public
       ownsService(service)
   {
       for (uint i = 0; i < owners[service].length; i++) {
           if (owners[service][i] == account) {
               if (i != owners[service].length - 1) {
                   owners[service][i] = owners[service][owners[service].length - 1];
               }
               owners[service].length--;
               break;
           }
       }
   }

   /**
   * Sell Keys
   * Services have to authorize keys for sale.
   * Key owners can disable key selling at time
   * of sale to prevent re-selling.
   */
   function createSalesOffer(bytes32 key, address payable buyer, uint price, bool _canSell)
       public
       ownsKey(key)
       canSell(key)
   {
       //cancel trade offer & create sales offer
       cancelTradeOffer(key);
       salesOffers[key].buyer = buyer;
       salesOffers[key].price = price;
       salesOffers[key].canSell = _canSell;
   }

   function cancelSalesOffer(bytes32 key)
       public
       ownsKey(key)
   {
       salesOffers[key].buyer = address(0);
       salesOffers[key].price = 0;
       salesOffers[key].canSell = false;
   }

   function purchaseKey(bytes32 key)
       public
       payable
       canSell(key)
   {

      //require explicit authority to spend tokens on the purchasers behalf
      require(salesOffers[key].price <= msg.value, "purchaseKey() salesOffers[key].price error");
      require(salesOffers[key].buyer == msg.sender, "purchaseKey() salesOffers[key].buyer error");

      uint balanceBeforeTransfer = keys[key].owner.balance;
      keys[key].owner.transfer(salesOffers[key].price);
      msg.sender.transfer(msg.value-salesOffers[key].price);
      assert(keys[key].owner.balance == balanceBeforeTransfer + salesOffers[key].price);

      emit KeySold(key, keys[key].owner, msg.sender, salesOffers[key].price);
      keys[key].owner = msg.sender;

      //set canSell - allows for non-resellable keys
      keys[key].canSell = salesOffers[key].canSell;

      //remove sales offer
      cancelSalesOffer(key);
   }

   /**
   * Trade keys
   * both keys have to be authorized
   * to trade by their respective services.
   */
    function createTradeOffer(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        //cancel sales offer & create a trade offer
        cancelSalesOffer(have);
        tradeOffers[have] = want;
    }

   function cancelTradeOffer(bytes32 key)
       public
       ownsKey(key)
   {
       tradeOffers[key] = bytes32(0); //remove the tradeOffer
   }

    function tradeKey(bytes32 have, bytes32 want)
        public
        ownsKey(have)
        validKey(want)
        canTrade(have)
        canTrade(want)
    {
        require(tradeOffers[want] == have, "tradeKey() error");

        emit KeysTraded(want, have);
        //complete the trade
        keys[have].owner = keys[want].owner;
        keys[want].owner = msg.sender;

        //remove trade offer
        cancelTradeOffer(want);
    }

   /**
   * Manage Keys
   * Service owner can set key permissions
   * disabling sharing, trading, or selling
   * removes shared owners, active trade
   * offers, and active sales offers respectively
   *
   * Should also be able to get a key and service,
   * get a count of keys and services, and get
   * a key and service key from the respective
   * lists.
   */
   //service owner can set permissions
   function setKeyPermissions(
       bytes32 key,
       bool canShare_,
       bool canTrade_,
       bool canSell_)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keys[key].canShare = canShare_;
       if (canShare_ == false) {
           owners[key].length = 0;
       }

       keys[key].canTrade = canTrade_;
       if (canTrade_ == false) {
           tradeOffers[key] = bytes32(0);
       }

       keys[key].canSell = canSell_;
       if (canSell_ == false) {
           salesOffers[key].buyer = address(0);
           salesOffers[key].price = 0;
           salesOffers[key].canSell = false;
       }

   }

   function getServiceCount() public view returns (uint) {
       return serviceList.length;
   }

   function getKeyCount() public view returns (uint) {
       return keyList.length;
   }

   function getService(bytes32 service)
       public
       view
       validService(service)
       returns(string memory, address)
   {
      return (services[service].url, services[service].owner);
   }

   function getKey(bytes32 key)
       public
       view
       validKey(key)
       returns(address, bool, bool, bool, bytes32)
   {
      return (keys[key].owner,
              keys[key].canShare,
              keys[key].canTrade,
              keys[key].canSell,
              keys[key].service);
   }

   /**
   * Key Data
   * A service can store public data for its keys.
   */
   function setKeyData(bytes32 key, bytes32 dataKey, bytes32 dataValue)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       keyData[keccak256(abi.encodePacked(key,dataKey))] = dataValue;
   }

   function getKeyData(bytes32 key, bytes32 dataKey)
       public
       view
       validKey(key)
       returns (bytes32)
   {
       return keyData[keccak256(abi.encodePacked(key,dataKey))];
   }

   /**
   * ecrecover passthrough
   */
   function recoverAddress(
       bytes32 msgHash,
       uint8 v,
       bytes32 r,
       bytes32 s)
       public
       pure
       returns (address)
   {
     return ecrecover(msgHash, v, r, s);
   }

   /**
   * Logging & Messaging
   * functions for creating an auditable record of activity.
   * A service can log access from any of its keys.
   */
   function logAccess(bytes32 key, string memory data)
       public
       validKey(key)
       ownsService(keys[key].service)
   {
       emit Access(msg.sender, keys[key].service, key, now, data);
   }

   //services and keys can log messages to each other
   function message(bytes32 from, bytes32 to, string memory category, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
               isServiceOwner(from, msg.sender), "message() error 1");
       require(keys[to].owner != address(0) || services[to].owner != address(0), "message() error 2");

       emit Message(msg.sender, from, to, now, category, data);
   }

   //any key or service can log
   function log(bytes32 from, string memory data)
       public
   {
       require((keys[from].owner != address(0) && isKeyOwner(from, msg.sender)) ||
                isServiceOwner(from, msg.sender), "log() error");

       emit Log(msg.sender, from, now, data);
   }

}


One last compiler warning

One last compiler warning

pragma solidity ^0.4.23;

contract Migrations {
  address public owner;
  uint public last_completed_migration;

  modifier restricted() {
    if (msg.sender == owner) _;
  }

  constructor() public {
    owner = msg.sender;
  }

  function setCompleted(uint completed) public restricted {
    last_completed_migration = completed;
  }

  function upgrade(address new_address) public restricted {
    Migrations upgraded = Migrations(new_address);
    upgraded.setCompleted(last_completed_migration);
  }
}

pragma solidity ^0.4.23;

contract Migrations {
  address public owner;
  uint public last_completed_migration;

  modifier restricted() {
    if (msg.sender == owner) _;
  }

  constructor() {
    owner = msg.sender;
  }

  function setCompleted(uint completed) public restricted {
    last_completed_migration = completed;
  }

  function upgrade(address new_address) public restricted {
    Migrations upgraded = Migrations(new_address);
    upgraded.setCompleted(last_completed_migration);
  }
}


Remove unused SafeMath.sol import (#2823)

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Address.sol";
import "../utils/Context.sol";

/**
 * @title PaymentSplitter
 * @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware
 * that the Ether will be split in this way, since it is handled transparently by the contract.
 *
 * The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each
 * account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim
 * an amount proportional to the percentage of total shares they were assigned.
 *
 * `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the
 * accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the {release}
 * function.
 */
contract PaymentSplitter is Context {
    event PayeeAdded(address account, uint256 shares);
    event PaymentReleased(address to, uint256 amount);
    event PaymentReceived(address from, uint256 amount);

    uint256 private _totalShares;
    uint256 private _totalReleased;

    mapping(address => uint256) private _shares;
    mapping(address => uint256) private _released;
    address[] private _payees;

    /**
     * @dev Creates an instance of `PaymentSplitter` where each account in `payees` is assigned the number of shares at
     * the matching position in the `shares` array.
     *
     * All addresses in `payees` must be non-zero. Both arrays must have the same non-zero length, and there must be no
     * duplicates in `payees`.
     */
    constructor(address[] memory payees, uint256[] memory shares_) payable {
        require(payees.length == shares_.length, "PaymentSplitter: payees and shares length mismatch");
        require(payees.length > 0, "PaymentSplitter: no payees");

        for (uint256 i = 0; i < payees.length; i++) {
            _addPayee(payees[i], shares_[i]);
        }
    }

    /**
     * @dev The Ether received will be logged with {PaymentReceived} events. Note that these events are not fully
     * reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the
     * reliability of the events, and not the actual splitting of Ether.
     *
     * To learn more about this see the Solidity documentation for
     * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback
     * functions].
     */
    receive() external payable virtual {
        emit PaymentReceived(_msgSender(), msg.value);
    }

    /**
     * @dev Getter for the total shares held by payees.
     */
    function totalShares() public view returns (uint256) {
        return _totalShares;
    }

    /**
     * @dev Getter for the total amount of Ether already released.
     */
    function totalReleased() public view returns (uint256) {
        return _totalReleased;
    }

    /**
     * @dev Getter for the amount of shares held by an account.
     */
    function shares(address account) public view returns (uint256) {
        return _shares[account];
    }

    /**
     * @dev Getter for the amount of Ether already released to a payee.
     */
    function released(address account) public view returns (uint256) {
        return _released[account];
    }

    /**
     * @dev Getter for the address of the payee number `index`.
     */
    function payee(uint256 index) public view returns (address) {
        return _payees[index];
    }

    /**
     * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the
     * total shares and their previous withdrawals.
     */
    function release(address payable account) public virtual {
        require(_shares[account] > 0, "PaymentSplitter: account has no shares");

        uint256 totalReceived = address(this).balance + _totalReleased;
        uint256 payment = (totalReceived * _shares[account]) / _totalShares - _released[account];

        require(payment != 0, "PaymentSplitter: account is not due payment");

        _released[account] = _released[account] + payment;
        _totalReleased = _totalReleased + payment;

        Address.sendValue(account, payment);
        emit PaymentReleased(account, payment);
    }

    /**
     * @dev Add a new payee to the contract.
     * @param account The address of the payee to add.
     * @param shares_ The number of shares owned by the payee.
     */
    function _addPayee(address account, uint256 shares_) private {
        require(account != address(0), "PaymentSplitter: account is the zero address");
        require(shares_ > 0, "PaymentSplitter: shares are 0");
        require(_shares[account] == 0, "PaymentSplitter: account already has shares");

        _payees.push(account);
        _shares[account] = shares_;
        _totalShares = _totalShares + shares_;
        emit PayeeAdded(account, shares_);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Address.sol";
import "../utils/Context.sol";
import "../utils/math/SafeMath.sol";

/**
 * @title PaymentSplitter
 * @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware
 * that the Ether will be split in this way, since it is handled transparently by the contract.
 *
 * The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each
 * account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim
 * an amount proportional to the percentage of total shares they were assigned.
 *
 * `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the
 * accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the {release}
 * function.
 */
contract PaymentSplitter is Context {
    event PayeeAdded(address account, uint256 shares);
    event PaymentReleased(address to, uint256 amount);
    event PaymentReceived(address from, uint256 amount);

    uint256 private _totalShares;
    uint256 private _totalReleased;

    mapping(address => uint256) private _shares;
    mapping(address => uint256) private _released;
    address[] private _payees;

    /**
     * @dev Creates an instance of `PaymentSplitter` where each account in `payees` is assigned the number of shares at
     * the matching position in the `shares` array.
     *
     * All addresses in `payees` must be non-zero. Both arrays must have the same non-zero length, and there must be no
     * duplicates in `payees`.
     */
    constructor(address[] memory payees, uint256[] memory shares_) payable {
        require(payees.length == shares_.length, "PaymentSplitter: payees and shares length mismatch");
        require(payees.length > 0, "PaymentSplitter: no payees");

        for (uint256 i = 0; i < payees.length; i++) {
            _addPayee(payees[i], shares_[i]);
        }
    }

    /**
     * @dev The Ether received will be logged with {PaymentReceived} events. Note that these events are not fully
     * reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the
     * reliability of the events, and not the actual splitting of Ether.
     *
     * To learn more about this see the Solidity documentation for
     * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback
     * functions].
     */
    receive() external payable virtual {
        emit PaymentReceived(_msgSender(), msg.value);
    }

    /**
     * @dev Getter for the total shares held by payees.
     */
    function totalShares() public view returns (uint256) {
        return _totalShares;
    }

    /**
     * @dev Getter for the total amount of Ether already released.
     */
    function totalReleased() public view returns (uint256) {
        return _totalReleased;
    }

    /**
     * @dev Getter for the amount of shares held by an account.
     */
    function shares(address account) public view returns (uint256) {
        return _shares[account];
    }

    /**
     * @dev Getter for the amount of Ether already released to a payee.
     */
    function released(address account) public view returns (uint256) {
        return _released[account];
    }

    /**
     * @dev Getter for the address of the payee number `index`.
     */
    function payee(uint256 index) public view returns (address) {
        return _payees[index];
    }

    /**
     * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the
     * total shares and their previous withdrawals.
     */
    function release(address payable account) public virtual {
        require(_shares[account] > 0, "PaymentSplitter: account has no shares");

        uint256 totalReceived = address(this).balance + _totalReleased;
        uint256 payment = (totalReceived * _shares[account]) / _totalShares - _released[account];

        require(payment != 0, "PaymentSplitter: account is not due payment");

        _released[account] = _released[account] + payment;
        _totalReleased = _totalReleased + payment;

        Address.sendValue(account, payment);
        emit PaymentReleased(account, payment);
    }

    /**
     * @dev Add a new payee to the contract.
     * @param account The address of the payee to add.
     * @param shares_ The number of shares owned by the payee.
     */
    function _addPayee(address account, uint256 shares_) private {
        require(account != address(0), "PaymentSplitter: account is the zero address");
        require(shares_ > 0, "PaymentSplitter: shares are 0");
        require(_shares[account] == 0, "PaymentSplitter: account already has shares");

        _payees.push(account);
        _shares[account] = shares_;
        _totalShares = _totalShares + shares_;
        emit PayeeAdded(account, shares_);
    }
}


Update Chess.sol

Update Chess.sol

Added makeTemporaryMove(), its fingerprint and some commentary to it. It includes castling (Rochade) at the moment.

/**
 * 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 {
    int8[128] defaultState = [int8(-4),int8(-2),int8(-3),int8(-5),int8(-6),int8(-3),int8(-2),int8(-4),int8(0),int8(0),int8(0),int8(4),int8(0),int8(0),int8(0),int8(0),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(4),int8(2),int8(3),int8(5),int8(6),int8(3),int8(2),int8(4),int8(0),int8(0),int8(0),int8(116),int8(0),int8(0),int8(0),int8(0)];

    struct Game {
        address player1;
        address player2;
        string player1Alias;
        string player2Alias;
        address nextPlayer;
        address playerWhite; // Player that is white in this game
        address winner;
        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[uint(Flag.FLAG_NAME)]
     * Directions[Direction.UP]
     */
    enum Direction { UP, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT }
    int8[8] Directions = [int8(-16), int8(-15), int8(1), int8(17), int8(16), int8(15), int8(-1), int8(-17)];
    enum Piece { WHITE_KING, WHITE_QUEEN, WHITE_ROOK, WHITE_BISHOP, WHITE_KNIGHT, WHITE_PAWN, EMPTY, BLACK_KING, BLACK_QUEEN, BLACK_ROOK, BLACK_BISHOP, BLACK_KNIGHT, BLACK_PAWN }
    int8[13] Pieces = [int8(-6), int8(-5), int8(-4), int8(-3), int8(-2), int8(-1), int8(0), int8(6), int8(5), int8(4), int8(3), int8(2), int8(1)];
    enum Player { WHITE, BLACK }
    int8[2] Players = [int8(1), int8(-1)];
    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}
    int8[9] Flags = [int8(123), int8(11), int8(16), int8(78), int8(79), int8(62), int8(63), int8(61), int8(77)];

    int8[8] knight_moves = [int8(-33), int8(-31), int8(-18), int8(-14), int8(14), int8(18), int8(31), int8(33)];

    function Chess() {
        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);

    /**
     * Convenience function to set a flag
     * Usage: setFlag(gameId, Flag.BLACK_KING_POS, 4);
     */
    function setFlag(bytes32 gameId, Flag flag, uint value) internal {
        games[gameId].state[uint(Flags[uint(flag)])] = int8(value);
    }

    /**
     * Convenience function to set a flag
     * Usage: setFlag(gameId, Flag.BLACK_KING_POS, 4);
     */
    function getFlag(bytes32 gameId, Flag flag) internal returns (int8) {
        return games[gameId].state[uint(Flags[uint(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 state
        games[gameId].state = defaultState;

        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 P2
            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);
    }

    /* 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[uint(Player.WHITE)];
        } else {
            currentPlayerColor = Players[uint(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
        validateMove(gameId, fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

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

        //makeTemporaryMove

        //isLegal

        //testIfCheck

        // Update state
        games[gameId].state[toIndex] = games[gameId].state[fromIndex];
        games[gameId].state[fromIndex] = 0;

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

        Move(gameId, msg.sender, fromIndex, toIndex);
    }

    function sanityCheck(uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 currentPlayerColor) {
        // check if the move actually fits the data structure
        if ((toIndex & 0x88) != 0) {
            throw;
        }

        // check if the move tries to move a figure onto it self
        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
        // todo: fix color to enum
        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) {
        int8 direction = getDirection(fromIndex, toIndex);
        bool isDiagonal = !(abs(direction) == 16 || abs(direction) == 1);

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

            throw;
        }

        // Bishops, Queens, Rooks
        if (abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_BISHOP)]) ||
            abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_QUEEN)]) ||
            abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_ROOK)])) {

            if (!isDiagonal && abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_BISHOP)]) ||
                isDiagonal && abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_ROOK)])) {
                return;
            }

            // Traverse all fields in direction
            int temp = int(fromIndex);
            while (temp & 0x88 != 0) {
                if (uint(temp) == toIndex) {
                    return;
                }
                temp += direction;
            }

            throw;
        }

        // Pawns
        if (abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_PAWN)])) {
            // Black can only move in positive, White negative direction
            if (fromFigure == Pieces[uint(Piece.BLACK_PAWN)] && direction < 0 ||
                fromFigure == Pieces[uint(Piece.WHITE_PAWN)] && direction > 0) {
                throw;
            }
            // Forward move
            if (!isDiagonal) {
                if (abs(direction) < 2) {
                    throw;
                }
                // simple move
                if (int(fromIndex) + direction == int(toIndex)) {
                    return;
                }
                // 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) {
                        return;
                    }
                }
                throw;
            }
            // 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[uint(Piece.BLACK_PAWN)] &&
                        getFlag(gameId, Flag.WHITE_EN_PASSANT) == int(toIndex) ||
                        fromFigure == Pieces[uint(Piece.WHITE_PAWN)] &&
                        getFlag(gameId, Flag.BLACK_EN_PASSANT) == int(toIndex)) {
                        return;
                    }
                }
                // If not empty
                return;
            }

            throw;
        }

        // Knights
        if (abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_KNIGHT)])) {
            for (uint i; i < knight_moves.length; i++) {
                if (int(fromIndex) + knight_moves[i] == int(toIndex)) {
                    return;
                }
            }
            throw;
        }

        throw;
    }

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

        // as long as we do not reach the desired position
        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 kind
            if (shouldCheckForCheck && checkForCheck(gameId, uint(currentIndex), currentPlayerColor)) {
                throw;
            }
            currentIndex = currentIndex + direction;
        }
        return;
    }

    function checkForCheck(bytes32 gameId, uint256 kingAtIndex, int8 currentPlayerColor) returns (bool) {
        // TODO
        return true;
    }

    function getDirection(uint256 fromIndex, uint256 toIndex) 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[uint(Direction.UP)];
            }
            if (isSameHorizontal){
                return Directions[uint(Direction.LEFT)];
            }
            if (isLeftSide){
                return Directions[uint(Direction.UP_LEFT)];
            } else {
                return Directions[uint(Direction.UP_RIGHT)];
            }
        } else {
            if (isSameVertical){
                return Directions[uint(Direction.DOWN)];
            }
            if (isSameHorizontal){
                return Directions[uint(Direction.RIGHT)];
            }
            if (isLeftSide){
                return Directions[uint(Direction.DOWN_LEFT)];
            } else{
                return Directions[uint(Direction.DOWN_RIGHT)];
            }
        }
    }

        function makeTemporaryMove(bytes32 gameId, uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure){
            games[gameId].state[uint(Flags[uint(Flag.WHITE_EN_PASSANT)])] = -1;
            games[gameId].state[uint(Flags[uint(Flag.WHITE_EN_PASSANT)])] = -1;

            // <---- Special Moves ---->

            // castling
            // it already passed valid we just need to move the rook

            // Black
            if (fromFigure == Pieces[uint(Piece.BLACK_KING)]){
                Flags[uint(Flag.BLACK_KING_POS)] = int8(toIndex);
                if ((fromIndex == 4)&&(toIndex == 1)){
                    games[gameId].state[0] = 0;
                    games[gameId].state[2] = Pieces[uint(Piece.BLACK_ROOK)];
                }
                if ((fromIndex == 4)&&(toIndex == 6)){
                    games[gameId].state[7] = 0;
                    games[gameId].state[5] = Pieces[uint(Piece.BLACK_ROOK)];
                }

            }
            // White
            if (fromFigure == Pieces[uint(Piece.WHITE_KING)]){
                Flags[uint(Flag.WHITE_KING_POS)] = int8(toIndex);
                if ((fromIndex == 116)&&(toIndex == 112)){
                    games[gameId].state[112] = 0;
                    games[gameId].state[114] = Pieces[uint(Piece.BLACK_ROOK)];
                }
                if ((fromIndex == 116)&&(toIndex == 118)){
                    games[gameId].state[118] = 0;
                    games[gameId].state[117] = Pieces[uint(Piece.BLACK_ROOK)];
                }

            }

    function isLegal() {

    }

    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);
    }

    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(Direction dir) internal returns (bool){
      if(abs(Directions[uint(dir)]) == 16)
        return false;
      if(abs(Directions[uint(dir)]) == 1)
        return false;
      return true;
    }

    /* 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 {
    int8[128] defaultState = [int8(-4),int8(-2),int8(-3),int8(-5),int8(-6),int8(-3),int8(-2),int8(-4),int8(0),int8(0),int8(0),int8(4),int8(0),int8(0),int8(0),int8(0),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(-1),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(1),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(0),int8(4),int8(2),int8(3),int8(5),int8(6),int8(3),int8(2),int8(4),int8(0),int8(0),int8(0),int8(116),int8(0),int8(0),int8(0),int8(0)];

    struct Game {
        address player1;
        address player2;
        string player1Alias;
        string player2Alias;
        address nextPlayer;
        address playerWhite; // Player that is white in this game
        address winner;
        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[uint(Flag.FLAG_NAME)]
     * Directions[Direction.UP]
     */
    enum Direction { UP, UP_RIGHT, RIGHT, DOWN_RIGHT, DOWN, DOWN_LEFT, LEFT, UP_LEFT }
    int8[8] Directions = [int8(-16), int8(-15), int8(1), int8(17), int8(16), int8(15), int8(-1), int8(-17)];
    enum Piece { WHITE_KING, WHITE_QUEEN, WHITE_ROOK, WHITE_BISHOP, WHITE_KNIGHT, WHITE_PAWN, EMPTY, BLACK_KING, BLACK_QUEEN, BLACK_ROOK, BLACK_BISHOP, BLACK_KNIGHT, BLACK_PAWN }
    int8[13] Pieces = [int8(-6), int8(-5), int8(-4), int8(-3), int8(-2), int8(-1), int8(0), int8(6), int8(5), int8(4), int8(3), int8(2), int8(1)];
    enum Player { WHITE, BLACK }
    int8[2] Players = [int8(1), int8(-1)];
    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}
    int8[9] Flags = [int8(123), int8(11), int8(16), int8(78), int8(79), int8(62), int8(63), int8(61), int8(77)];

    int8[8] knight_moves = [int8(-33), int8(-31), int8(-18), int8(-14), int8(14), int8(18), int8(31), int8(33)];

    function Chess() {
        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);

    /**
     * Convenience function to set a flag
     * Usage: setFlag(gameId, Flag.BLACK_KING_POS, 4);
     */
    function setFlag(bytes32 gameId, Flag flag, uint value) internal {
        games[gameId].state[uint(Flags[uint(flag)])] = int8(value);
    }

    /**
     * Convenience function to set a flag
     * Usage: setFlag(gameId, Flag.BLACK_KING_POS, 4);
     */
    function getFlag(bytes32 gameId, Flag flag) internal returns (int8) {
        return games[gameId].state[uint(Flags[uint(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 state
        games[gameId].state = defaultState;

        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 P2
            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);
    }

    /* 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[uint(Player.WHITE)];
        } else {
            currentPlayerColor = Players[uint(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
        validateMove(gameId, fromIndex, toIndex, fromFigure, toFigure, currentPlayerColor);

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

        //makeTemporaryMove

        //isLegal

        //testIfCheck

        // Update state
        games[gameId].state[toIndex] = games[gameId].state[fromIndex];
        games[gameId].state[fromIndex] = 0;

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

        Move(gameId, msg.sender, fromIndex, toIndex);
    }

    function sanityCheck(uint256 fromIndex, uint256 toIndex, int8 fromFigure, int8 toFigure, int8 currentPlayerColor) {
        // check if the move actually fits the data structure
        if ((toIndex & 0x88) != 0) {
            throw;
        }

        // check if the move tries to move a figure onto it self
        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
        // todo: fix color to enum
        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) {
        int8 direction = getDirection(fromIndex, toIndex);
        bool isDiagonal = !(abs(direction) == 16 || abs(direction) == 1);

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

            throw;
        }

        // Bishops, Queens, Rooks
        if (abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_BISHOP)]) ||
            abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_QUEEN)]) ||
            abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_ROOK)])) {

            if (!isDiagonal && abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_BISHOP)]) ||
                isDiagonal && abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_ROOK)])) {
                return;
            }

            // Traverse all fields in direction
            int temp = int(fromIndex);
            while (temp & 0x88 != 0) {
                if (uint(temp) == toIndex) {
                    return;
                }
                temp += direction;
            }

            throw;
        }

        // Pawns
        if (abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_PAWN)])) {
            // Black can only move in positive, White negative direction
            if (fromFigure == Pieces[uint(Piece.BLACK_PAWN)] && direction < 0 ||
                fromFigure == Pieces[uint(Piece.WHITE_PAWN)] && direction > 0) {
                throw;
            }
            // Forward move
            if (!isDiagonal) {
                if (abs(direction) < 2) {
                    throw;
                }
                // simple move
                if (int(fromIndex) + direction == int(toIndex)) {
                    return;
                }
                // 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) {
                        return;
                    }
                }
                throw;
            }
            // 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[uint(Piece.BLACK_PAWN)] &&
                        getFlag(gameId, Flag.WHITE_EN_PASSANT) == int(toIndex) ||
                        fromFigure == Pieces[uint(Piece.WHITE_PAWN)] &&
                        getFlag(gameId, Flag.BLACK_EN_PASSANT) == int(toIndex)) {
                        return;
                    }
                }
                // If not empty
                return;
            }

            throw;
        }

        // Knights
        if (abs(fromFigure) == uint(Pieces[uint(Piece.BLACK_KNIGHT)])) {
            for (uint i; i < knight_moves.length; i++) {
                if (int(fromIndex) + knight_moves[i] == int(toIndex)) {
                    return;
                }
            }
            throw;
        }

        throw;
    }

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

        // as long as we do not reach the desired position
        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 kind
            if (shouldCheckForCheck && checkForCheck(gameId, uint(currentIndex), currentPlayerColor)) {
                throw;
            }
            currentIndex = currentIndex + direction;
        }
        return;
    }

    function checkForCheck(bytes32 gameId, uint256 kingAtIndex, int8 currentPlayerColor) returns (bool) {
        // TODO
        return true;
    }

    function getDirection(uint256 fromIndex, uint256 toIndex) 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[uint(Direction.UP)];
            }
            if (isSameHorizontal){
                return Directions[uint(Direction.LEFT)];
            }
            if (isLeftSide){
                return Directions[uint(Direction.UP_LEFT)];
            } else {
                return Directions[uint(Direction.UP_RIGHT)];
            }
        } else {
            if (isSameVertical){
                return Directions[uint(Direction.DOWN)];
            }
            if (isSameHorizontal){
                return Directions[uint(Direction.RIGHT)];
            }
            if (isLeftSide){
                return Directions[uint(Direction.DOWN_LEFT)];
            } else{
                return Directions[uint(Direction.DOWN_RIGHT)];
            }
        }
    }

    function makeTemporaryMove() {

    }

    function isLegal() {

    }

    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);
    }

    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(Direction dir) internal returns (bool){
      if(abs(Directions[uint(dir)]) == 16)
        return false;
      if(abs(Directions[uint(dir)]) == 1)
        return false;
      return true;
    }

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


Update totalSupply; allow updates to totalSupply when official star db changes


fix * /

fix * /

pragma solidity ^0.4.0;
contract PotOfGold {

    struct Pot {
        string name;
        uint buyIn;

        address[] players;

        uint lastPlayerBlockNumber; // uint8(uint256(sha3(block.blockhash(lastPlayerBlockNumber+1)))) % 3 == loser index

        address loser;
    }

    address owner;

    Pot[] allPots;
    mapping(address => Pot[]) playerToPots;
    mapping(string => Pot) nameToPot;

    function PotOfGold() {
        owner = msg.sender;
    }

    function ownerWithdraw(){
        if(msg.sender != owner) throw;

        int toWithdraw = this.balance - 100 finney; // leave 0.1 ether for gas (?)
        if(toWithdraw < 0) throw;

        owner.send(toWithdraw);
    }

    function getMyPots() constant returns (Pot[]){
        return playerToPots(msg.sender);
    }

    function getAllPots() constant returns (Pot[]){
        return allPots;
    }

    function getPot(string name) constant returns (Pot){
        return nameToPot[name];
    }

    function createPot(string name, uint buyIn) {
        if(buyIn == 0) throw; // must bet something
        if(bytes(name).length == 0) throw; // name mustn't be empty
        if(nameToPot[name].buyIn != 0) throw; // there's already a pot with this name

        Pot pot = nameToPot[name];
        pot.name = name;
        pot.buyIn = buyIn;
        pot.players.push(msg.sender);
        pot.buyIn = buyIn;

        allPots.push(pot);
        playerToPots[msg.sender].push(pot);
    }

    function joinPot(string name) {
        Pot pot = nameToPot[name];
        if(pot.buyIn == 0) throw; // no pot
        if(pot.loser != 0) throw; // pot is over
        if(pot.players.length == 3) throw; // pot is full but waiting for a loser
        if(msg.value != pot.buyIn) throw; // must bet buyin amount

        pot.players.push(msg.sender);
        if(pot.players.length == 3){
           pot.lastPlayerBlockNumber = block.number;
        }
    }

    /*function leavePot(string name) {
        Pot pot = nameToPot[name];
        if(pot.buyIn == 0) throw; // no pot
        if(pot.loser != 0) throw; // pot is over
        if(pot.players.length == 3) throw; // pot is full but waiting for a loser

        if(pot.players[0] != msg.sender && pot.players[1] != msg.sender) throw; // no such player in pot

        address[] newPlayers;
        for(uint i = 0; i < pot.players.length; i++){
            if(pot.players[i] != msg.sender){
                newPlayers.push(pot.players[i]);
            }
        }

        pot.players = newPlayers;

        msg.sender.send((pot.buyIn * 99) / 100); // leaving fee 1%
    }*/

    function solvePot(string name){
        Pot pot = nameToPot[name];
        if(pot.loser != 0) throw; // pot is over
        if(pot.players.length < 3) throw; // pot not full
        if(block.number <= pot.lastPlayerBlockNumber) throw;

        bytes32 blockHash = block.blockhash(pot.lastPlayerBlockNumber + 1);
        if(blockHash == 0) { // pot expired due to hash storage limits - players didn't solve pot
            pot.loser = msg.sender; // doesn't matter, everybody loses a fee

            for(uint i = 0; i < pot.players.length; i++){
                pot.players[i].send((pot.buyIn * 99) / 100); // return money minus 1% fee
            }

            return;
        }

        bytes32 potShaResult = sha3(msg.sender, blockHash);
        uint8 loserIndex = uint8(uint256(potShaResult) % 3);

        address winner1 = pot.players[(loserIndex + 1) % 3];
        address winner2 = pot.players[(loserIndex + 2) % 3];

        uint winAmount = ((pot.buyIn / 2) * 99) / 100;
        uint returnAmount = pot.buyIn + winAmount;

        winner1.send(returnAmount);
        winner2.send(returnAmount);
    }
}

pragma solidity ^0.4.0;
contract PotOfGold {

    struct Pot {
        string name;
        uint buyIn;

        address[] players;

        uint lastPlayerBlockNumber; // uint8(uint256(sha3(block.blockhash(lastPlayerBlockNumber+1)))) % 3 == loser index

        address loser;
    }

    address owner;

    Pot[] allPots;
    mapping(address => Pot[]) playerToPots;
    mapping(string => Pot) nameToPot;

    function PotOfGold() {
        owner = msg.sender;
    }

    function ownerWithdraw(){
        if(msg.sender != owner) throw;

        int toWithdraw = this.balance - 100 finney; // leave 0.1 ether for gas (?)
        if(toWithdraw < 0) throw;

        owner.send(toWithdraw);
    }

    function getMyPots() constant returns (Pot[]){
        return playerToPots(msg.sender);
    }

    function getAllPots() constant returns (Pot[]){
        return allPots;
    }

    function getPot(string name) constant returns (Pot){
        return nameToPot[name];
    }

    function createPot(string name, uint buyIn) {
        if(buyIn == 0) throw; // must bet something
        if(bytes(name).length == 0) throw; // name mustn't be empty
        if(nameToPot[name].buyIn != 0) throw; // there's already a pot with this name

        Pot pot = nameToPot[name];
        pot.name = name;
        pot.buyIn = buyIn;
        pot.players.push(msg.sender);
        pot.buyIn = buyIn;

        allPots.push(pot);
        playerToPots[msg.sender].push(pot);
    }

    function joinPot(string name) {
        Pot pot = nameToPot[name];
        if(pot.buyIn == 0) throw; // no pot
        if(pot.loser != 0) throw; // pot is over
        if(pot.players.length == 3) throw; // pot is full but waiting for a loser
        if(msg.value != pot.buyIn) throw; // must bet buyin amount

        pot.players.push(msg.sender);
        if(pot.players.length == 3){
           pot.lastPlayerBlockNumber = block.number;
        }
    }

    /*function leavePot(string name) {
        Pot pot = nameToPot[name];
        if(pot.buyIn == 0) throw; // no pot
        if(pot.loser != 0) throw; // pot is over
        if(pot.players.length == 3) throw; // pot is full but waiting for a loser

        if(pot.players[0] != msg.sender && pot.players[1] != msg.sender) throw; // no such player in pot

        address[] newPlayers;
        for(uint i = 0; i < pot.players.length; i++){
            if(pot.players[i] != msg.sender){
                newPlayers.push(pot.players[i]);
            }
        }

        pot.players = newPlayers;

        msg.sender.send((pot.buyIn * 99) / 100); // leaving fee 1%
    }*/

    function solvePot(string name){
        Pot pot = nameToPot[name];
        if(pot.loser != 0) throw; // pot is over
        if(pot.players.length < 3) throw; // pot not full
        if(block.number <= pot.lastPlayerBlockNumber) throw;

        bytes32 blockHash = block.blockhash(pot.lastPlayerBlockNumber + 1);
        if(blockHash == 0) { // pot expired due to hash storage limits - players didn't solve pot
            pot.loser = msg.sender; // doesn't matter, everybody loses a fee

            for(uint i = 0; i < pot.players.length; i++){
                pot.players[i].send((pot.buyIn * 99) / 100); // return money minus 1% fee
            }

            return;
        }

        bytes32 potShaResult = sha3(msg.sender, blockHash);
        uint8 loserIndex = uint8(uint256(potShaResult) % 3);

        address winner1 = pot.players[(loserIndex + 1) % 3];
        address winner2 = pot.players[(loserIndex + 2) % 3];

        uint winAmount = ((pot.buyIn * / 2) * 99) / 100;
        uint returnAmount = pot.buyIn + winAmount;

        winner1.send(returnAmount);
        winner2.send(returnAmount);
    }
}