contract TokenGame {
    address public owner;
    uint public cap_in_wei;
    uint constant initial_duration = 1 hours;
    uint constant time_extension_from_doubling = 1 hours;
    uint constant time_of_half_decay = 1 hours;
    Token public excess_token; /* Token contract used to receive excess after the sale */
    Withdraw public excess_withdraw;  /* Withdraw contract distributing the excess */
    Token public game_token;   /* Token contract used to receive prizes */
    uint public end_time;      /* Current end time */
    uint last_time = 0;        /* Timestamp of the latest contribution */
    uint256 ema = 0;           /* Current value of the EMA */
    uint public total_wei_given = 0;  /* Total amount of wei given via fallback function */

    function TokenGame(uint _cap_in_wei) {
        owner = msg.sender;
        cap_in_wei = _cap_in_wei;
        excess_token = new Token(1);
        excess_withdraw = new Withdraw(excess_token);
        game_token = new Token(2);
        end_time = now + initial_duration;
    }

    function play() payable {
        require(now <= end_time);   // Check that the sale has not ended
        require(msg.value > 0);     // Check that something has been sent
        total_wei_given += msg.value;
        ema = msg.value + ema * time_of_half_decay / (time_of_half_decay + (now - last_time) );
        last_time = now;
        uint extended_time = now + ema * time_extension_from_doubling / total_wei_given;
        if (extended_time > end_time) {
            end_time = extended_time;
        }
        if (!excess_token.mint(msg.sender, msg.value) || !game_token.mint(msg.sender, msg.value)) {
            throw;
        }
    }

    function finalise() {
        require(now > end_time);
        excess_token.seal();
        game_token.seal();
        uint to_owner = 0;
        if (this.balance > cap_in_wei) {
            to_owner = cap_in_wei;
            if (!excess_withdraw.send(this.balance - cap_in_wei)) {
                throw;
            }
        } else {
            to_owner = this.balance;
        }
        if (to_owner > 0) {
            if (!owner.send(to_owner)) {
                throw;
            }
        }
    }
}
function TokenGame(uint _cap_in_wei) {
    owner = msg.sender;
    cap_in_wei = _cap_in_wei;
    excess_token = new Token(1);
    excess_withdraw = new Withdraw(excess_token);
    game_token = new Token(2);
    end_time = now + initial_duration;
}

/* Total amount of wei given via fallback function */