<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>sterlingwest</title>
	<atom:link href="http://sterlingwest.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://sterlingwest.wordpress.com</link>
	<description>Just another WordPress.com site</description>
	<lastBuildDate>Thu, 23 Feb 2012 13:33:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='sterlingwest.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>sterlingwest</title>
		<link>http://sterlingwest.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://sterlingwest.wordpress.com/osd.xml" title="sterlingwest" />
	<atom:link rel='hub' href='http://sterlingwest.wordpress.com/?pushpress=hub'/>
		<item>
		<title>ACM-Queue 2012 ICPC Challenge</title>
		<link>http://sterlingwest.wordpress.com/2012/02/23/acm-queue-2012-icpc-challenge/</link>
		<comments>http://sterlingwest.wordpress.com/2012/02/23/acm-queue-2012-icpc-challenge/#comments</comments>
		<pubDate>Thu, 23 Feb 2012 00:28:01 +0000</pubDate>
		<dc:creator>sterlingwest</dc:creator>
				<category><![CDATA[Competitions]]></category>

		<guid isPermaLink="false">http://sterlingwest.wordpress.com/?p=6</guid>
		<description><![CDATA[First of all, I would like to thank the organizers, participants, and everyone else involved. I really enjoyed working on and developing my submission for this contest. I&#8217;ve participated in several competitions similar in style to this one in the past, but this is the first time I&#8217;ve won one. This write up is intended [&#8230;]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sterlingwest.wordpress.com&#038;blog=31837235&#038;post=6&#038;subd=sterlingwest&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>First of all, I would like to thank the organizers, participants, and everyone else involved. I really enjoyed working on and developing my submission for this contest. I&#8217;ve participated in several competitions similar in style to this one in the past, but this is the first time I&#8217;ve won one.</p>
<p>This write up is intended to give a general overview of both the strategy I had in developing my bot, and also the strategy (or lack of one) my bot uses.</p>
<p>I&#8217;ve put the <a href="http://dl.dropbox.com/u/40886345/ACMBot.java">source code</a> up on DropBox. It&#8217;s become a mess over its short lifetime. =) If you do anything cool with it, be sure to let me know.</p>
<h2>Strategy</h2>
<p>Coercion is one of those domains where I find that trying to find a strategy is somewhat difficult. Instead of building a strategy for it, I wanted the bot&#8217;s behavior to be as emergent as possible. Each turn my bot generates a list of tasks that it might want to consider. Each pusher then selects from that list, attempting to maximize an estimated value with respect to the cost of that action (measured in relative time to task completion.)</p>
<p>scoreOfAction = optionValue/optionCost;</p>
<p>The greatest of these scores is the action which the bot performs. This is done in a greedy manner, and I&#8217;ve structured my code as follows:</p>
<ol>
<li>Read in pre-game input</li>
<li>Calculate static game attributes</li>
<li>For each turn:
<ol>
<li>Read in input</li>
<li>Calculate dynamic game attributes</li>
<li>Consider all possible &#8220;candidate moves&#8221; for each pusher.
<ul>
<li>Select the one with the best estimated value.</li>
</ul>
</li>
<li>Actuate each pusher&#8217;s selected move</li>
</ol>
</li>
</ol>
<p>The specific calculations are probably the strangest, and I don&#8217;t talk about them in detail, but here&#8217;s the list of what is being calculated:</p>
<p><em><strong>Static Calculations</strong></em></p>
<ul>
<li>Region Sizes</li>
<li>Region Centers</li>
<li>Edge Centers</li>
<li>Region Slopes</li>
<li>Postability of Vertices (We can&#8217;t place a marker on a vertex that only touches very steep regions [Unless we get very very lucky!])</li>
</ul>
<p><em><strong>Dynamic Calculations</strong></em></p>
<ul>
<li>Marker Locations (What regions are they touching?)</li>
<li>Marker/Region Pressure</li>
<li>Marker Post Values (For &#8220;posted&#8221; markers, how helpful or hurtful is it for us to leave the marker there.)</li>
<li>Estimated Placement Values
<ul>
<li>Each Target (see Candidate Moves) has a value associated with having a particularly colored marker touching it.</li>
<li>This value is negative for blue markers, positive for red markers, and can be positive or negative for grays, depending on the target&#8217;s regions&#8217; colors.</li>
<li>The magnitude of the value is exponentially greatest when the region is most easily captured.</li>
</ul>
</li>
</ul>
<hr />
<h2>Candidate Moves</h2>
<p>Every turn we need to make a decision as to what to do. As my code ended up, every turn each pusher redecided from scratch. In reality, this is the area that could be most easily expanded upon, but I only ended up having 3 different types of actions. In my code (and in this write up) I refer to a list of &#8220;Targets.&#8221; The set of Targets are:</p>
<ul>
<li>Every Region</li>
<li>Every Vertex that is postable, and is not on one of the four map boundaries</li>
<li>Every Edge that is not on one of the four map boundaries</li>
</ul>
<p>Each target represents a possible location that a marker can be moved to.</p>
<h2>Option 1: Place a Marker</h2>
<p>Every turn my bot considers every possible pairing of Markers and Targets that satisfy the following:</p>
<ul>
<li>The Marker isn&#8217;t Blue (My opponent&#8217;s)</li>
<li>The Target contains at least one region (or is a region) of the color of the marker</li>
</ul>
<p>If the pairing satisfies the above, then the value and cost is calculated simply as:</p>
<blockquote><p>optionValue = Target.placementValue[Marker.Color]-Marker.postScore;<br />
if(Target.postedMarker != Marker) { optionValue -= Target.placementValue[Target.postedMarker.Color]; }</p>
<p>optionCost = euclideanDistance(Marker,Target)+euclideanDistance (Pusher,Marker)/2;</p></blockquote>
<p>Notice that this allows for gray markers to be placed on a region. In this manner, my bot will actively and aggressively place gray markers to &#8220;capture&#8221; blue territory in the name of gray.</p>
<h2>Option 2: Capture a Marker</h2>
<p>Every turn I consider every Gray and  Blue Marker that is touching at least one region that satisfies either:</p>
<ul>
<li>The region is not red; or</li>
<li>The region might soon stop being red</li>
</ul>
<p>The value and cost associated with capturing that marker is:</p>
<blockquote><p>optionValue = MarkerValue(ourCount) &#8211; Marker.postScore;<br />
if(Marker.Color == Blue){ optionValue += MarkerValue(theirCount); }</p>
<p>optionCost = euclideanDistance(Marker, Home)+euclideanDistance (Pusher,Marker)/2;</p></blockquote>
<p>The function &#8220;MarkerValue(x) &#8221; calculates the the value of having a marker, provided we already have &#8220;x&#8221; markers. The more markers we have, the less helpful it is to have more. I use an exponential function for this. The function also gives a bonus value if it&#8217;s earlier in the game. This bonus additive and linear, equaling &#8220;900-turnNum&#8221; (Turns range from 1 to 900).</p>
<h2>Option 3: Displace a Marker</h2>
<p>This was an amusing addition to watch. Consider every marker that is presently posted:</p>
<blockquote><p>optionValue = -1*Marker.postScore;</p>
<p>optionCost = euclideanDistance(Pusher,Marker)/2;</p></blockquote>
<hr />
<h2>Actuating a Move</h2>
<p>Great, now what? For most of the  actuation I used a modified version of what was included in the Migrate example, I just made the nudges a little more violent, depending on distances to the target, and what was being done. For those readers not familiar with the sample code, it works as follows:</p>
<h2>MoveTo(Pusher, Destination)</h2>
<p>This was included in the sample bot. Our goal here is pretty straightforward. We have a pusher (which is probably already moving) and a destination we would like it to reach. In an ideal world we&#8217;d be moving at maximum velocity directly toward the destination. However if we simply try to apply a maximal force vector to the bot in the direction of the destination, then we&#8217;ll merely end up homing in on the destination, slowly converging towards it. It would be nice if we could get there a little more precisely.</p>
<p>MoveTo first applies force to cancel out any of the component of the Pusher&#8217;s current velocity that is perpendicular to the &#8220;ideal&#8221; motion. If the force applied to the perpendicular component is less than the maximum force we&#8217;re allowed to apply, then it constructs another vector pointing in the &#8220;ideal&#8221; direction with magnitude equal to the remaining allowed force and vector sums the two together.</p>
<h2>MoveAround(Pusher, Marker, Destination)</h2>
<p>This code first calculates if we are already &#8220;behind&#8221; the Marker. It determines this by looking at the normalized vector from the Marker to the Pusher (The vector pointing from the marker to the pusher, but scaled down to have a length of one), and the normalized vector from the Marker to the Destination. The dot product of these two vectors will range from -1 to 1, where 1 means the pusher is on the same side of the Marker as the Destination is, and -1 means that the Marker is directly in between the Pusher and the Destination. The default is that the pusher is &#8220;behind&#8221; the marker if the dot product is less than -.8. I changed this to -.9 in my bot.</p>
<p>If the pusher is behind the marker, then MoveAround immediately returns true. Otherwise it returns false after selecting an alternate destination next to the marker that will help it get closer to the other side, and calling: MoveTo(Pusher, AlternateDestination);</p>
<h2>Place a Marker</h2>
<p>To place a marker we need to first get behind the marker, and then ram into the marker repeatedly in order to knock it to where we want it. We can now easily accomplish this using the above methods as follows:</p>
<blockquote><p>if( MoveAround(Pusher, Marker, Target) ) { MoveTo(Pusher, Marker); }</p></blockquote>
<h2>Capture a Marker</h2>
<p>This is exactly like placing a marker, except that we&#8217;re placing it on our home region. So it is as follows:</p>
<blockquote><p>if( MoveAround(Pusher, Marker, Home) ){ MoveTo(Pusher, Marker) ; }</p></blockquote>
<h2>Displace a Marker</h2>
<p>All we want to do is remove the marker from its lofty perch. So we want to hit it as hard as we can:</p>
<blockquote><p>MoveTo(Pusher,Marker);</p></blockquote>
<h2>Pathing</h2>
<p>As amusing as it is to watch the cute little pushers carefully place a marker, then plow right through it to get to their next destination, it&#8217;s not so helpful in a practical sense. My bot paths around markers that are in its way, in an &#8220;approximately correct&#8221; manner.</p>
<p>I modified the MoveTo code to first consider every marker that could be in a pusher&#8217;s way, choosing the closest of these. I consider that a marker could be in a pusher&#8217;s way if the Dot Product of the normal vectors <strong>MarkerToPusher</strong> and <strong>MarkerToDestination</strong> is less than .1 . If the closest such marker is less than 10 units away, then perform an analogous calculation to the MoveAround method, and move to a location nearby the offending marker first.</p>
<p>Now, this isn&#8217;t perfect, and often pushers will &#8220;nick&#8221; markers as they go around, however this is uncommon and even when it happens it&#8217;s rarely an issue. Also if you watch carefully, you&#8217;ll notice that the pushers will occasionally veer  slightly off-track to &#8220;graze&#8221; tangentially along a nearby marker. While this is definitely not optimal, the lost time here is very insignificant, and the overall behavior seems to be very good.</p>
<h2>What I didn&#8217;t do, but would&#8217;ve if I had more time</h2>
<p>Target pruning! This is a big one! In the specifications it mentions that the number of markers and regions could be as large as 200 each! My bot would almost certainly time out under such conditions. The change needed here is, during static calculation, only create a target list as large as some formula that takes into account the number of markers. I wouldn&#8217;t want to decrease the number of markers considered, however it&#8217;s really not <em>necessary</em> to consider every region as a target for placement.</p>
<p>Saving Markers. The code is in there to consider &#8220;Saving&#8221; a marker if it&#8217;s close to being captured as a possible action, but it caused some erroneous behavior when pushing a marker temporarily over neutral territory (the pusher would suddenly consider it at risk of being captured) So some added check would be necessary to make it work well.</p>
<p>Placing markers in areas not partially controlled by me. A couple of bots employed this behavior (notably Coke Chan did so aggressively) and it&#8217;s something I wanted to do myself. However I never got around to figuring out a good value/cost heuristic for these cases. (Obviously it&#8217;s less valuable than the apparent value, as you&#8217;re risking a marker.)</p>
<p>Pusher-Task selection priorities. Atm, if Pusher 1 is performing task A, and Pusher 2 is performing task B, and Pusher 1 completes task A, it will likely consider task B to be very necessary and kick Pusher 2 off of its task. This often causes my bot to have some weird behavior that may be hard to explain without this knowledge. Basically, Pusher 1 shouldn&#8217;t have unconditional preemptive power over the other Pushers as it presently stands.</p>
<h2>Conclusions</h2>
<p>That&#8217;s pretty much it. No doubt I&#8217;ve hand waved some details, but I think most of them could be worked out / reversed engineered from the source code (should one be so brave.)  Hopefully at least some people got something from reading this, and many thanks again to everyone in the competition! I know at least I learned a lot, and I hope to see some of you in future competitions. =)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/sterlingwest.wordpress.com/6/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/sterlingwest.wordpress.com/6/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=sterlingwest.wordpress.com&#038;blog=31837235&#038;post=6&#038;subd=sterlingwest&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://sterlingwest.wordpress.com/2012/02/23/acm-queue-2012-icpc-challenge/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/5b069dc0b9a58c83d4e4ec7216ce988b?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">sterlingwest</media:title>
		</media:content>
	</item>
	</channel>
</rss>
