2012年2月26日 星期日

2012 Queue ICPC Challenge

This is the second time I join this kind of competition. It is happy and fun to compete with all of you. Here, I write a summary of my player program. Please feel free to ask if you have any question, or you just want to share idea with me. Looking forward to see your sharing. (^^)



Major Idea

The idea of the program is to assign 'command' to pusher.
At the beginning of the game, all 3 pushers are idle.
Each pusher takes a command from the command queue, 
then executes it until it reach the 'command completed' condition.
After that, the pusher becomes idle again, and takes another command from queue again.
These process repeat and repeat, until the end of game.


Major Flow

The flow of game mainly implemented as follows:
read the game state
append command to the command queue
FOR EACH pusher
    check if my command finish, if yes, I am idle now
    IF idle THEN
        take a command from command queue
        prepare parameter for the command
        create command object and assign to me
    END IF
    execute my command
END FOR


Command

Commands
The program uses the following 2 commands:
BRING_HOME_COMMAND
    1. Get the nearest markers(in pusher point of view) that is grey or blue
    2. Take the markers to point (10, 10)
    3. 'command completed' condition: 
        - marker fall into region (0,0) (20,20); or
        - marker becomes red already; or
        - command has been execute over 100 rounds
PUT_COMMON_VERTEX_COMMAND
    1. Calculate common vertex
        - Each vertex has a count, store how many region share this vertex
        - Vertex list is then sorted by this count descendingly
    2. Get the nearest markers(in pusher point of view) that is red
    3. Get the vertex:
        - loop through vertex list
        - find the highest count which has no red markers already near it
    4. Take the markers to vertex point
    5. 'command completed' condition: 
        - marker reach to vertex point; or
        - marker becomes non-red accidentally; or
        - command has been execute over 100 rounds



Command queue
The command queue has nearly no logic, and implemented as follows:
 

IF queue size smaller than 4 THEN
    Add DO_BRING_HOME_COMMAND to end of queue
    Add DO_BRING_HOME_COMMAND to end of queue
    Add PUT_COMMON_VERTEX_COMMAND to end of queue
    Add PUT_COMMON_VERTEX_COMMAND to end of queue
    Add PUT_COMMON_VERTEX_COMMAND to end of queue
    Add PUT_COMMON_VERTEX_COMMAND to end of queue
END IF



p.s. 
I want to create more clever commands. Unfortunality, before the submission deadline, I still cannot make a command that can win the combination of these two (><) .




Pusher movement

The program has an important feature that is to let a pusher takes a marker to a target location.
It is done in following 4 steps:

STEP1: Move Around
    - Pusher will move very near to marker, but not touching marker

STEP2: Move To a point opposite to the target
    - Pusher will slightly move to the opposite position that can push the marker
    - In another word, after doing step2, target, marker and pusher will be in a straight line
    - See the graph below:


STEP3: For far away from target, push marker hardly
    - Create a hit point. This is the point pusher and marker will have a collision. After that marker should move to a direction to the target.
    - Create a virtual point. This is a point where pusher will 'want to' move to. With a far away  virtual point, pusher will have a greater force to hit the marker.
    - Of course, pusher will not move to virtual point actually since there will have collision.
    - See the graph below:
         

STEP4: For nearby target, push marker softly
    - Simliar to STEP3
    - Since the target is closer, the virtual point is nearer, in order to make the force weaker
    - See the graph below:
   






Formula 

Formula to calculate hit point:
diff.x = abs ( marker.x - target.x )
diff.y = abs ( marker.y - target.y )
hit_point.x = marker.x + 2 * sin ( atan ( diff.x / diff.y ) )
hit_point.y = marker.y + 2 * cos ( atan ( diff.x / diff.y ) )

Formula to calculate virtual point:
distance = sqrt ( sqr( marker.x - target.x ) + sqr( marker.y - target.y ) )
diff.x = abs ( hit_point.x - pusher.x )
diff.y = abs ( hit_point.y - pusher.y )
virtual_point.x = hit_point.x + distance * sin ( atan ( diff.x / diff.y ) )
virtual_point.y = hit_point.y + distance * cos ( atan ( diff.x / diff.y ) )



where
    - abs means absoluate value
   
- sin means sine
   
- cos means cosine
   
- atan means arctangent
    - sqr means square of a number
   
- sqrt means square root of a number