 package Organisms2.g4;

class SimpleEntity extends Entity {
    final int d_heading;
    final int e_clone;
    final int r_move;
    final int f_clone;
    
    int last_move_age = -1000;

    public SimpleEntity( int[] param, int key ) {
        super( param );


        int heading = key & 0x3 ;

        double x = Math.random();
        if ( x <= 0.01 )
            d_heading = turnLeft( heading );
        else if ( x > 0.99 )
            d_heading = turnRight( heading );
        else
            d_heading = heading;

        if ( key == -1 )
            setYear( 0 );
        else
            setYear( (key>>16) & 0xffff );

        f_clone = ev * 10 / eu;

        int _r_move = (key==-1) ? (ev-1) : 
            (int)( ( Math.random() * 0.2 + 0.9 )
                   * descale( decode( (key>>2) & 0x7f, 7 ), ev ) );

        double ratio = (double)ev/(double)eu;
        int _e_clone = em/2;
        if ( ratio > 0.75 )
        {
            _e_clone = (int)( em * ( Math.random() * 0.5 + 0.5 ) );
        }
        else if ( ratio >= 0.4 )
        {
            if ( year() < 100 )
                _e_clone = (int)( em * ( Math.random() * 0.5 + 0.2 ) );
            else
                _e_clone = (int)( em * ( Math.random() * 0.5 + 0.4 ) );
        }
        else if ( ratio >= 0.15 )
        {
            if ( year() < 100 )
                _e_clone = (int)( em * ( Math.random() * 0.4 + 0.15 ) );
            else
                _e_clone = (int)( em * ( Math.random() * 0.6 + 0.2 ) );
        }
        else
        {
            if ( year() < 100 )
                _e_clone = (int)( em * ( Math.random() * 0.4 + 0.1 ) );
            else if ( year() < 1000 )
                _e_clone = (int)( em * ( Math.random() * 0.4 + 0.5 ) );
            else
                _e_clone = (int)( em * ( Math.random() * 0.2 + 0.7 ) );
            if ( year() > 2000 )
                _r_move *= 2;
            if ( year() > 10000 )
                _r_move *= 2;
        }

        if ( year() > 20000 )
        {
            _r_move *= 4;
            _e_clone = (int)( em * (Math.random() * 0.1 + 0.85 ) );
        }

        r_move = _r_move;
        e_clone = _e_clone;
/*
        r_move = ( ev <= 1 ) ? 0 :
            ( ev/2 + (int) ( ev * 3.0 / ( generation + 1 ) ) );

        
        e_clone = (int) ( em * ( Math.sqrt( Math.random() ) * 0.5 
                                 + 1.0/(generation+1) * 0.25
                                 + 0.2 ) );

        double r = Math.random();
        double y = 0.5;
        if ( r >= 0.6 )
            y = 1.0;
        else if ( r < 0.4 )
            y = 0.0;

        double factor = 4.0/(generation*4.0+1);

        e_clone = (int) ( em * ( 0.85 * y 
                                 + 0.15 * ( (1-factor)*y + factor*0.5 ) ) );
*/
    }

    public int action() {
        int ret;

        if ( hungry() )
        {
            ret = action_findfood();
            if ( ret >= 0 )
                return ret;
        }

        if ( energy() > e_clone || food() > f_clone )
        {
            if ( sameEntity( turnBack( d_heading ) ) )
                ret = action_move();
            else
                ret = action_clone();

            if ( ret >= 0 )
                return ret;
        }

        if ( 0 == food() )
        {
            ret = action_move();
            if ( ret >= 0 )
                return ret;
        }

        return STAY;
    }

    private int action_clone() {
        int left = turnLeft( d_heading );
        int right = turnRight( d_heading );
        int ret;

        if ( hasEntity( d_heading ) && sameEntity( d_heading ) )
        {
            if ( Math.random() < 0.5 ) 
            {
                int tmp = left;
                left = right;
                right = tmp;
            }

            if ( hasFood( right ) )
            {
                ret = action_clone_alt( right );
                if ( ret >= 0 )
                    return ret;
            }
            ret = action_clone_alt( left );
            if ( ret >= 0 )
                return ret;
            ret = action_clone_alt( right );
            if ( ret >= 0 )
                return ret;
            return -1;
        }

        if ( hasFood( right ) )
        {
            ret = action_clone( right );
            if ( ret >= 0 )
                return ret;
        }

        ret = action_clone( left );
        if ( ret >= 0 )
            return ret;
        ret = action_clone( right );
        if ( ret >= 0 )
            return ret;

        return -1;
    }

    private void setCloneAttr( int d, double x0, double x1 ) {
        setCloneAttr( ( d & 3 ) | ( year()<<16 )
                      | encode( x0, 7 ) << 9
                      | encode( x1, 7 ) << 2
            );
    }

    private int action_clone( int d ) {
        if ( hasEntity(d) )
            return -1;
        setCloneAttr( d, enscale( r_move, ev ), (double)e_clone/(double)em );
        return CLONE | d;
    }

    private int action_clone_alt( int d ) {
        if ( hasEntity(d) )
            return -1;
        setCloneAttr( d_heading, enscale( r_move, ev ), 
                      (double)e_clone/(double)em );
        return CLONE | d;
    }

    private int action_findfood() {
        int ret;
        if ( food() > 0 )
            return STAY;

        ret = action_findfood( d_heading );
        if ( ret >= 0 )
            return ret;
        ret = action_findfood( turnLeft( d_heading ) );
        if ( ret >= 0 )
            return ret;
        ret = action_findfood( turnRight( d_heading ) );
        if ( ret >= 0 )
            return ret;
        ret = action_findfood( turnBack( d_heading ) );

        return ret;
    }

    private int action_findfood( int d ) {
        if ( !hungry() )
            return -1;

        if ( food() > 0 )
            return -1;

        if ( !hasFood( d ) )
            return -1;

        return MOVE | d;
    }

    private int action_move() {
        if ( last_move_age + r_move >= age() )
            return -1;

        last_move_age = age();

        int ret = action_move( d_heading );
        if ( ret != -1 )
            return ret;
        ret = action_move( turnLeft(d_heading) );
        if ( ret != -1 )
            return ret;
        ret = action_move( turnRight(d_heading) );
        if ( ret != -1 )
            return ret;
        ret = action_move( turnBack(d_heading) );
        return ret;
    }

    private int action_move( int d ) {
        if ( hasEntity( d ) )
            return -1;
        return MOVE | d;
    }
}
