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