<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
	<title>Artificial Intelligence - Articles</title>
	<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/</link>
	<pubDate>Sat, 25 Feb 2012 22:09:44 +0000</pubDate>
	<ttl>43200</ttl>
	<description>Resources for enabling intelligent agents in games and game environments</description>
	<item>
		<title>Navigation Graph Generation</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/navigation-graph-generation-r2805</link>
		<description><![CDATA[<strong class='bbc'><span style='font-size: 18px;'>Overview</span></strong><br />
<br />
Navigation graph remains a useful alternative to navigation mesh and may offer certain advantages depending on a game's environment. This article discusses several approaches to navigation graph generation: from an automated one based on Delaunay triangulation to a completely automatic method derived from triangulation of navigable areas and dual graph of triangulation.<br />
<br />
The article uses general computational geometry algorithms and also algorithms inspired by image processing. An open source computer vision library OpenCV ([Bradski2008], [OCV]) may be used to implement image processing-based techniques discussed here.<br />
<br />
We also touch on hierarchical navigation graphs that open important optimization opportunities.<br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Introduction: Navigation Meshes and Graphs </span></strong><br />
<br />
There is a growing number of middle-ware products handling navigation of game agents. We are not going to review or even attempt to mention any of them. While they may provide solid solutions for many typical situations, building a custom navigation system may be still the only viable option for many projects. Hence it is important to understand what techniques engineers and designers can choose from.<br />
<br />
There are two main approaches to creating and supplying navigation (aka "routing", or "pathfinding") information for game levels. One is based on navigation meshes and the other is using the navigation graph (see general overview of the methods to represent navigation data in [Stout2000] and also [Snook2000] for navigation meshes in particular). Figure 1 below shows examples of both kinds of navigation data representing a navigable area for the same test environment.<br />
 <br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3700-0-92686900-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3700" title="Fig01A.png - Size: 14.32K, Downloads: 466"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-63277200-1309293937_thumb.png" id='ipb-attach-img-3700-0-92686900-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig01A.png" /></a> <a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3701-0-92761400-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3701" title="Fig01B.png - Size: 32.26K, Downloads: 669"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-38221900-1309293938_thumb.png" id='ipb-attach-img-3701-0-92761400-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig01B.png" /></a><br />
<strong class='bbc'>Figure 1. Navigation Mesh and Navigation Graph with a path connecting points A and B.</strong></p><br />
<p class='bbc_left'><br />
<span style='font-size: 14px;'><strong class='bbc'>Navigation Mesh </strong></span><br />
<br />
Agents in game can use a navigation mesh to find the path from location A to location B by an algorithm which we outline in very general terms. First, given the initial agent's location A, the algorithm finds what triangle Ta of the mesh contains A and what triangle Tb contains B (the destination). Then, a shortest path across the mesh can be built. This path is a list L of connected triangles from triangle Ta to triangle Tb. Usually this is done using A* (a-star) algorithm (see [Matthews2002] for an excellent introduction into A*).<br />
<br />
Since any paths inside navigation triangles are valid, knowing the list L allows us to connect A to B with a piece-wise linear path. Hence, the calculation of L accomplishes our task, at least in its first rough approximation. Usually further manipulations of the path are desirable as this rough path looks too robotic. This issue is quite obvious from the figure above. While improving aesthetics of the path is a fascinating topic, we will not go any deeper on this.<br />
<br />
Navigation meshes can often be naturally derived from collision geometry in an automated or completely automatic manner. It can be updated in run time as well, but this may be challenging due to the performance constraints unless we deal with only small portions of the mesh at a time.<br />
<br />
<span style='font-size: 14px;'><strong class='bbc'>Navigation Graph</strong></span><br />
<br />
Navigation graph approaches the problem of building navigation data from a dual perspective. Yet the techniques involved are often similar in many ways to a mesh-based approach.<br />
Namely, the graph is based on nodes, which are not intended to cover all navigable geometry but rather provide useful markers and serve as waypoints. A set of 2D primitives (circles, quads and the like) can be used to represent nodes in a navigation graph. Any path inside a node is considered valid. Also, a path (usually - a straight line) from any point in the environment to any point inside any node is considered to be valid provided it satisfies some additional constraints. The most common constraint is that the path does not intersect collision geometry. Additionally, we may exclude high drops, too steep slopes, water surfaces, etc.<br />
<br />
More often than not, checking against collision and other terrain properties along the path could be expensive. Such checks can be replaced by checking against much simpler representations of un-navigable geometry via blocking primitives. The blocking primitives are by far less-detailed and are often limited to boxes (oriented or axis-aligned) and cylinders. This allows for very efficient testing of ray intersection against blocking primitives. Note that the navigation mesh usually doesn’t require addition of blocking primitives as all information about the navigable area is already included in the navigation mesh.<br />
<br />
Below, Figure 2 shows an example of blocking primitives which are semi transparent red axis-aligned boxes with white outlines placed along the walls, trash cans and other obstacles. The navigation graph has yellow-green nodes connected with bright yellow edges. The area shown approximately corresponds to the lower left corner of the test environment on Figure 1. (The door is not unlocked yet so there is no connection to the indoors part of the test environment.)<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3702-0-92781600-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3702" title="Fig02.jpg - Size: 115.91K, Downloads: 672"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-67176700-1309294168_thumb.jpg" id='ipb-attach-img-3702-0-92781600-1330207784' style='width:233;height:200' class='attach' width="233" height="200" alt="Attached Image: Fig02.jpg" /></a><br />
<strong class='bbc'>Figure 2 Blocking Primitives and Navigation Graph (Environment model: courtesy of Inna Cherneykina.)</strong><br />
 </p><br />
<p class='bbc_left'>Given a navigation graph and a set of blocking primitives, we can construct a path using the following algorithm: From starting point A we look for the closest navigation node Na such that the line of view from A to Na is not blocked by any primitive. In a similar manner we find node Nb for destination point B. Then using a-star we find a list of nodes connecting Na to Nb. On the figure below the navigation graph from Figure 1 is shown together with blocking primitives (pale pink boxes).<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3703-0-92811300-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3703" title="Fig03.png - Size: 32.96K, Downloads: 330"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-37259600-1309294269_thumb.png" id='ipb-attach-img-3703-0-92811300-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig03.png" /></a><br />
<strong class='bbc'>Figure 3 Navigation Graph and Blocking Primitives</strong><br />
 </p><br />
<p class='bbc_left'>Navigation graphs may offer certain advantages over navigation meshes. To start with, the graph can easily incorporate navigation slots of objects placed into the environment. Say, we need an agent to approach a door and orient itself in a certain way to successfully open it. With navigation graphs the slots indicating desired position near the door can become just another node in the graph, likely with some additional attributes (orientation, and may also contain an indication of what type of animation to use for opening the door, etc.)<br />
<br />
Second, since the navigation graph is not tied to the level geometry in the same direct way as navigation mesh, it can offer extra flexibility during level design. The nodes are usually represented as objects in the level design tools. As such they can be easier manipulated than triangles in a navigation mesh where designers should care about preserving topological properties of the mesh. By tweaking graph nodes location the designer can introduce certain subtle (and not so subtle) desirable effects influencing pathing in the environment.<br />
<br />
Needless to say, manual generation of a navigation graph and its tweaking can be very time consuming. Another downside is that such handcrafted graphs are difficult to update if the geometry changes during the design process and they require extra care in case of run-time modifications in game.<br />
<br />
Summarizing, we may conclude that a navigation mesh is more appropriate when navigation data is generated automatically and a navigation graph may be more preferred when level designers’ input is needed or necessary. This leads to the necessity of simplifying creation and maintenance of the navigation graph when it is subject to manual modification.<br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Manual creation of navigation graph and its validation </span></strong><br />
<br />
There are several technical considerations to take into account while creating a navigation graph.<br />
<br />
<span style='font-size: 14px;'><strong class='bbc'>Optimal density of the graph </strong></span><br />
<br />
On one hand the graph has to be dense enough in the environment to provide navigable nodes accessible from each valid location. On the other hand an excessively-detailed graph is hard to build manually and may lead to longer a-star calculation times. Also it tends to result in a robotic look of agents: they tend to stick to nodes without taking obvious shortcuts.<br />
<br />
Surprisingly a sparse graph may also lead to an increase of run-time calculations or even breaking down of the algorithm if it does not take into consideration the following situation – see Figure 4.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3704-0-92840000-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3704" title="Fig04.png - Size: 7.63K, Downloads: 482"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-96840600-1309294269_thumb.png" id='ipb-attach-img-3704-0-92840000-1330207784' style='width:165;height:200' class='attach' width="165" height="200" alt="Attached Image: Fig04.png" /></a><br />
<strong class='bbc'>Figure 4 Picking nearest node on the other side of the wall</strong><br />
 </p><br />
<p class='bbc_left'>On Figure 4 the agent is placed at location A. When looking for the nearest node it would pick the one highlighted in red. Obviously it is the wrong node to start a path with. Hence a sanity check for intersection of the ray agent-selected node against blocking primitives would be needed to prevent the agent running into the wall on its way to the highlighted node. But then, if the selected node is rejected, we need to find another one which is nearby yet reachable directly. There may be an expensive calculation involved in this additional search, depending on the complexity of the environment.<br />
<br />
Hence an off-line procedure validating the navigation graph may also check for such gaps in the graph rather than rely on run-time code to recover from lack of nodes.<br />
<br />
<span style='font-size: 14px;'><strong class='bbc'>Taking into account finite size of the agents</strong></span><br />
<br />
Next, edges of the navigation graph have to be placed in such a way that following along them would keep agents sufficiently far from any collision geometry. Generally, as soon as an agent reaches node <strong class='bbc'>N<sub class='bbc'><em class='bbc'>i</em></sub></strong> on its path, it can immediately turn towards the next node <strong class='bbc'>N<sub class='bbc'><em class='bbc'>i+1</em></sub></strong>, see Figure 5. On this figure collision with geometry outlined by a blocking primitive may occur along the highlighted path from A to B. On the left side of this Figure some paths between <strong class='bbc'>N<sub class='bbc'><em class='bbc'>i</em></sub></strong> and <strong class='bbc'>N<sub class='bbc'><em class='bbc'>i+1</em></sub> </strong>are ok but many are blocked as shown.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3705-0-92856900-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3705" title="Fig05a.png - Size: 6.2K, Downloads: 236"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-55634200-1309294270_thumb.png" id='ipb-attach-img-3705-0-92856900-1330207784' style='width:250;height:167' class='attach' width="250" height="167" alt="Attached Image: Fig05a.png" /></a> <a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3706-0-92874400-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3706" title="Fig05b.png - Size: 6.9K, Downloads: 284"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-17973900-1309294271_thumb.png" id='ipb-attach-img-3706-0-92874400-1330207784' style='width:250;height:167' class='attach' width="250" height="167" alt="Attached Image: Fig05b.png" /></a><br />
<strong class='bbc'>Figure 5 Transition between nodes:<br />
(left) the agent may turn at distance R from the node center;<br />
(right) a wider corridor has to be clear of obstacles.</strong><br />
 </p><br />
<p class='bbc_left'>Thus, it's not only the edges of the graph but a wider area between each of the two connected nodes has to be clear of obstacles. This area is a 2D cylinder with the bases at the nodes and sides defined by external mutual tangents. It is not always easy to satisfy this requirement when creating a navigation graph manually.<br />
<br />
A useful technique to keep agents from coming too close to the walls is a method based on Minkowski sums and is widely adopted in robotics [deBerg2010]. The main idea behind this approach can be explained in simplified terms as follows: Suppose that an agent has a bounding sphere of radius R, which we will also call the agent’s radius. Apparently we want to keep an agent away from walls at a distance of at least R. Also suppose that originally blocking primitives were created exactly aligned with the collision geometry. If we "inflate" the primitives by adding R on each side along each dimension, and shrink the navigable area correspondingly by the same amount, we may represent the agent as a point. Conveniently this will keep the agent away from the actual collision geometry during navigation. The procedure of inflating blocking primitives and shrinking navigable areas can be done automatically in the development pipeline (preferably) or in run-time. The figure below illustrates this technique. Lighter-color blocking primitives were obtained from original ones using such inflation.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3707-0-92893600-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3707" title="Fig06.png - Size: 29.82K, Downloads: 363"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-81792600-1309294271_thumb.png" id='ipb-attach-img-3707-0-92893600-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig06.png" /></a><br />
<strong class='bbc'>Figure 6 Inflated Blocking Primitives (light red) overlaid with original<br />
primitives (dark red) and navigation graph</strong><br />
 </p><br />
<p class='bbc_left'>To summarize this section, it is better to avoid completely manual creation of navigation graphs as it is an error-prone and time-consuming process. As an alternative we should look for completely automatic techniques or, sometimes, the combination of manual steps with automated procedures. From this perspective it was worth outlining manual steps of navigational graph creation to flesh out the main constraints.  <br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Connecting nodes via triangulation algorithms  </span></strong><br />
<br />
Out of all manual steps, placing nodes without actually connecting them by edges is the easier and faster part of the task. Luckily it is possible to automate connecting existing nodes in an environment that already contains blocking primitives. Delaunay triangulation [deBerg2010] provides one of the possible solutions.<br />
<br />
Triangulation of a planar set of points connects them by edges in such a way that no edges intersect each other (planarity of connection graph) and no more edges can be added without breaking this condition (maximal property). Delaunay triangulation offers some additional benefits: it maximizes minimal angle of all the triangles in the triangulation. Thus it tends to produce least amount of “thin” triangles. This property by itself may not seem to be very important but it comes from the fact that Delaunay triangulation is a dual object for Voronoi diagram [deBerg2010].<br />
<br />
A Voronoi diagram of a discrete set of N points (nodes) on a plane can be defined as subdivision of the plane into N regions (aka Dirichlet domains) by finding the nearest node for each point on a plane. If a point is on equal distance <em class='bbc'><strong class='bbc'>d</strong></em> from two or more nodes <strong class='bbc'>N<sub class='bbc'><em class='bbc'>i1</em></sub>,…,N<sub class='bbc'><em class='bbc'>ik</em></sub></strong>, and no other nodes are closer than <em class='bbc'><strong class='bbc'>d</strong></em> then it belongs to the boundary of the corresponding domains.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3708-0-92911000-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3708" title="Fig07.png - Size: 44.24K, Downloads: 386"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-44434400-1309294272_thumb.png" id='ipb-attach-img-3708-0-92911000-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig07.png" /></a><br />
<strong class='bbc'>Figure 7 Voronoi cells and Delaunay Triangulation (no blocked edges<br />
removed) for the graph nodes</strong><br />
 </p><br />
<p class='bbc_left'>Voronoi diagrams appear naturally in tasks like optimal placement of retail stores in a neighborhood to minimize travel distance to them, or placing re-translators for wireless networks. Pretty much any modern book on computational geometry has at least a chapter or two on both Delaunay triangulation and Voronoi diagrams so we will not spend more time on the definitions or examples.<br />
<br />
A Voronoi diagram of the navigation nodes shows which node will be picked for each starting point when searching for the first node on the path hence its obvious importance for building navigation graphs and placing nodes. As a side note, consider Voronoi cells overlaid over blocking primitives in the problematic area from Figure 4<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3709-0-92928200-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3709" title="Fig08.png - Size: 9.01K, Downloads: 352"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-96251000-1309294272_thumb.png" id='ipb-attach-img-3709-0-92928200-1330207784' style='width:170;height:200' class='attach' width="170" height="200" alt="Attached Image: Fig08.png" /></a><br />
<strong class='bbc'>Figure 8 Voronoi cells overlaid over blocking primitives.<br />
Blue shaded cell extends beyond blocking primitive and creates problematic<br />
situation shown on Figure 4.</strong><br />
 </p><br />
<p class='bbc_left'>Such overlay of Voronoi cells over blocking primitives can easily reveal too sparse placement of the nodes with respect to the blocking primitives. A formal requirement for correct placement of nodes with respect to the primitives to ensure that all nearest nodes are immediately reachable is the following: If <strong class='bbc'>V </strong>is Voronoi cell corresponding to a node <strong class='bbc'>N</strong>, and <strong class='bbc'>Bi </strong>are blocking primitives, i=1,..,M, and <strong class='bbc'>&#092; </strong>is set-theoretical subtraction then we need a set <strong class='bbc'>V’ = V &#092; (union of all Bi) </strong>obtained by subtracting from V all of the blocking primitives to be convex and the node N must belong to it.<br />
<br />
There are a number of algorithms for building Delaunay triangulation and corresponding Voronoi subdivisions. For practical purposes we can use available implementations like the one coming with the OpenCV library [Bradski2008], [OCV]. Alternatively we can adopt implementations described in text books like [ORourke2000]. While sub-optimal in terms of complexity, these implementations provide sufficient performance for most practical purposes when the number of nodes is not too high. Using hierarchical graphs when possible will make Delaunay triangulation task tractable even for quite big environments.<br />
<br />
After Delaunay triangulation is built, the edges of the graph intersecting blocking primitives are removed. Removal of edges intersecting blocking primitives may uncover nodes placed problematically from the point of view of finding the nearest initial node in the graph. Connection between nodes C and D is conspicuously missing from the graph suggesting that Voronoi cells for these nodes may not have enough coverage to include all points like A on Figure 4. There are few more similarly missing edges of the graph and sure enough all of them indicate problems with nodes layout.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3710-0-92945500-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3710" title="Fig09a.png - Size: 27.23K, Downloads: 276"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-44629300-1309294273_thumb.png" id='ipb-attach-img-3710-0-92945500-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig09a.png" /></a> <a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3711-0-92962600-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3711" title="Fig09b.png - Size: 27.23K, Downloads: 269"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-05234100-1309294274_thumb.png" id='ipb-attach-img-3711-0-92962600-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig09b.png" /></a><br />
<strong class='bbc'>Figure 9 Navigation graphs obtained from Delaunay triangulation by<br />
removing edges blocked by primitives. “Missing” edges on the left (like<br />
between nodes C and D) indicate problematic placement of nodes fixed on<br />
the right version of the graph.</strong><br />
 </p><br />
<p class='bbc_left'>It is worth mentioning that hierarchical approach to graph construction and to the search of the nearest node alleviates the problem of picking the wrong initial node based on proximity alone. We will elaborate on this it in the section on hierarchical navigation graphs.<br />
<br />
Sometimes it is necessary to include particular edges into the final triangulation. This variation of the Delaunay triangulation problem is called constrained and is considerably more difficult [Seidel1988]. However, for navigation purposes, we may have enough freedom to just add new edges after the initial navigation graph is built.<br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Navigable areas from collision geometry </span></strong><br />
<br />
It is useful to extract navigable areas from collision geometry as a polygonal mesh regardless of what is the target representation: navigation graph or navigation mesh. Navigation mesh can be directly created from this data but the navigation graph would require several additional steps that we will discuss later.  <br />
<br />
To create such polygonal representation we may consider rendering collision geometry into a sufficiently high resolution bitmap. It can be achieved by running rendering in the modeling application used as a level design tool or procedurally, directly from the scene data.<br />
<br />
In most of the simpler cases the level geometry can be projected onto a plane without overlaps (e.g. a single floor of a building, or an outdoor terrain without caves or overhangs). The entire horizontal collision geometry can be rendered onto a horizontal plane using orthographic projection in one color (say, blue) and the vertical collision elements (walls and obstacles) can be rasterized as 1-pixel wide lines of different color (say, red), so that we can tell obstacles from navigable parts.<br />
<br />
Since there are so many variations on the tools and modeling applications used in game development, we will skip discussion of the rendering step. We will assume that we already have a reasonably detailed map of flat pieces of collision geometry. It is also necessary to obtain a coordinate transformation allowing conversion of pixel coordinates into in-game coordinates (say, (x,y) scene coordinates).<br />
<br />
Next after rendering, a flood fill algorithm in 2D raster image can be applied. Different variations of flood fill algorithms may work for this purpose. In OpenCV a result similar to flood fill may be achieved via (adaptive) threshold operation. (Look up cvThershold and cvAdaptiveThreshold: the first one will almost surely cover all your needs). We don’t go into details because of highly diverse source of the bitmaps due to the diversity of modeling tools and methods but the idea behind converting the rendered image into binary image of navigable areas is mostly self-evident and technically not too difficult.<br />
<br />
As an aside note, we may use the rendered source image to inflate one-pixel width blocking lines by half width of the max dimension of the agent radius. This can be done using OpenCV dilate operation. On the other hand, we can delay this until  later steps when we obtain polygonal representation of the navigable area.<br />
<br />
Polygonization of a binary image can be handled via contour detection. Here we outline the algorithm using Python (OpenCV now conveniently ships with pre-built Python binding).</p><ul class='bbcol decimal'><br /><li>Create binary image of the navigable area (namely, 8bit single channel black and white image) by rendering environment with appropriate settings. We start below with ready image on Figure 10.<br />	&nbsp;<br /></li><li>Run contours extraction. This requires steps:<br />	<blockquote><span style='font-family: Courier New'><span style='color: #000080'>image = cv.LoadImage(navigableArea)<br />	storage = cv.CreateMemStorage(0)<br />	contours = cv.FindContours(image, storage,<br />	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cv.CV_RETR_CCOMP, cv.CV_CHAIN_APPROX_SIMPLE)<br />	contours = cv.ApproxPoly(contours, storage, cv.CV_POLY_APPROX_DP, 3, 1)</span></span></blockquote><br /></li></ul><br />
A call to ApproxPoly simplifies found contours by converting them to polygons, which is exactly our goal. After this call we will have polygonal contours as list of vertices as (x,y) pairs of the first top level contour.<br />
<br />
Accessing siblings and nested contours via contours.v_next() and contours.h_next() would allow us to iterate through all the found contours. Another useful function is DrawContours. It provides an easy visualization of contours. Below on the Figure 10 we used custom visualization to show vertices.<br />
 <br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3712-0-92981500-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3712" title="Fig10a.png - Size: 3.51K, Downloads: 217"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-91362300-1309294288_thumb.png" id='ipb-attach-img-3712-0-92981500-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig10a.png" /></a> <a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3713-0-92999400-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3713" title="Fig10b.png - Size: 4.36K, Downloads: 195"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-29293300-1309294289_thumb.png" id='ipb-attach-img-3713-0-92999400-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig10b.png" /></a><br />
<strong class='bbc'>Figure 10 Extracting contours from binary image. The contours hierarchy<br />
has single contour on the top level and total depth =1 because of single<br />
inner contour (rotated rectangle).</strong><br />
 </p><br />
<p class='bbc_left'>We have several options on how to proceed next with building polygonal mesh from the contours. Ideally we want to obtain triangular mesh, and this is a well known problem of polygon triangulation [dBerg2010], [Orourke2000]. Our situation is a bit more complex as our polygons may have holes. Also one of our objectives is to have triangulation similar to Delaunay triangulation (no excessively skinny triangles). Yet using constrained Delaunay triangulation may be an algorithmic overkill. Though not optimal in terms of performance (complexity is at least that one of Delaunay triangulation), we may consider the following step:</p><ul class='bbc'><br /><li>Run Delaunay triangulation on the vertices of extracted contours. Tessellate Delaunay mesh using contours to include edges and corresponding triangles from the extracted contours (Figure 11).<br /></li></ul><br />
Tessellation must ensure that the resulting mesh is flat and triangular. The easiest way to achieve this is to intersect all contour edges with Delaunay tessellation vertices to check if there are non-trivial intersections indicating that the current mesh is not flat.<br />
 <br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3714-0-93017000-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3714" title="Fig11a.png - Size: 16.4K, Downloads: 167"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-86676300-1309294289_thumb.png" id='ipb-attach-img-3714-0-93017000-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig11a.png" /></a> <a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3715-0-93034200-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3715" title="Fig11b.png - Size: 17K, Downloads: 161"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-35064000-1309294290_thumb.png" id='ipb-attach-img-3715-0-93034200-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig11b.png" /></a><br />
<strong class='bbc'>Figure 11 Delaunay mesh with added contours on the left is not flat: points<br />
A and B mark intersecting edges. Adding vertices at the locations A and B<br />
and repeating triangulation  flattens the mesh (right).</strong><br />
 </p><br />
<p class='bbc_left'>Finally, we complete procedure with the step:</p><ul class='bbc'><br /><li>Eliminate edges and faces that are not covering navigable terrain (Figure 11 right). The result is shown on the Figure below.<br /></li></ul><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3716-0-93051900-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3716" title="Fig12.png - Size: 13.12K, Downloads: 144"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-75165400-1309294290_thumb.png" id='ipb-attach-img-3716-0-93051900-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig12.png" /></a><br />
<strong class='bbc'>Figure 12 Triangulation of navigable area. This mesh may be optionally<br />
optimized or tessellated further.</strong><br />
 </p><br />
<p class='bbc_left'>Concluding our discussion of extraction of the navigable area as a polygonal mesh, we should mention that OpenCV algorithms work particularly well with computer generated images such as those obtained from level design tools. This makes them a robust element of the game pipeline.<br />
<br />
As a side note, to compare this “sterile” setup with real world applications of OpenCV check out an article [Botana2010]. It provides an excellent coverage of contours detection and their handling. It is related to real-world images for augmented reality games. Working with images acquired with a camera is much more challenging.<br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Automatic placement of nodes for navigable areas </span></strong><br />
<br />
So far we completed triangulation of navigable area. Such triangular mesh can be easily converted into navigation mesh by augmenting it with explicit connectivity information if necessary. We could be done at this point if we decide to go with navigation mesh, but we can also use triangulation for building a navigation graph.<br />
<br />
<span style='font-size: 14px;'><strong class='bbc'>“Art gallery” navigation graph</strong></span><br />
<br />
Given some triangulation of the navigable area we can follow a minimalist approach and use the results of the art gallery theorem [deBerg2010], [ORourke200]. It asks for placing minimal number of guards in a polygonal shaped gallery so that all of the walls are seen by a guard. The additional twist here is that we may have holes in our polygonal representation so generally we are not dealing with simple polygons as in the basic art gallery theorem.<br />
<br />
The requirement of visibility posed by the art gallery theorem is exactly the one we want to satisfy for nodes on the first step of path finding (find nearest visible). If the nodes of the graph contain all of the guard locations then we have a graph which allows getting to a node from any navigable location. Note that the guards are not required to see each other so we may need to place additional nodes to complete the graph.<br />
<br />
The main step in proving of the art gallery theorem is to triangulate the polygon. Triangulation from inflated blocking primitives was completed in the previous section so we will use it to place the nodes corresponding to the guards. The vertices of the triangulation are valid node positions by construction.<br />
<br />
We can choose the first vertex arbitrarily or pick one of the highest order to cover maximum number of triangles. Next node can be placed by finding first triangle that is not entirely visible from any of the existing nodes.<br />
<br />
Next we need to check for visibility of nodes from each other and use mesh connectivity to place intermediate nodes to ensure that the graph is correctly connected. Below is an example of such graph.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3717-0-93069800-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3717" title="Fig13.png - Size: 19.02K, Downloads: 144"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-17003500-1309294291_thumb.png" id='ipb-attach-img-3717-0-93069800-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig13.png" /></a><br />
<strong class='bbc'>Figure 13 Graph based on Art Gallery Theorem</strong><br />
 </p><br />
<p class='bbc_left'>Despite being very small and yet valid representation of the navigable area, such a graph is not very useful as is. One of the main reasons is lots of backtracking that will occur during navigation with such graph i.e. agents would be often moving towards a node that is not in the intuitively correct direction of the goal. We discuss this issue in more details in the next section.<br />
<br />
<span style='font-size: 14px;'><strong class='bbc'>Dual graph approach</strong></span><br />
<br />
Dual graph of a triangular mesh [deBerg2010] can be another candidate for the navigation graph. It is built by associating a node with each triangle and then connecting nodes corresponding to the adjacent triangles. Geometrically, the nodes are usually placed at some internal point of the triangle, say, at its center of mass. Obviously, in such dual graph at least one of its nodes is "visible" from any point of the navigable area. However such graph may have problems as shown on the next Figure.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3718-0-93089500-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3718" title="Fig14.png - Size: 17.66K, Downloads: 190"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-64703800-1309294291_thumb.png" id='ipb-attach-img-3718-0-93089500-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig14.png" /></a><br />
<strong class='bbc'>Figure 14 Dual graph of triangulation. Red highlights show possible<br />
intersection of edges with blocking primitives.</strong><br />
 </p><br />
<p class='bbc_left'>The problem we encountered on the Figure above results from possible intersection of the edges of dual graph with blocking primitives. This can be relatively easy to detect and correct by connecting two triangles via an additional one of their common vertices. Also we can use inflated by the agent radius primitives to ensure that the edges of the dual graph are sufficiently far from the collision geometry.<br />
<br />
Additionally we can also include vertices and edges of the triangulation into the navigation graph. The result of adding edges connecting dual graph vertices with triangulation vertices and edges of the triangulation is shown below.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3719-0-93107100-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3719" title="Fig15.png - Size: 33.99K, Downloads: 199"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-14595500-1309294292_thumb.png" id='ipb-attach-img-3719-0-93107100-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig15.png" /></a><br />
<strong class='bbc'>Figure 15 Extension of dual graph to corresponding navigation graph. </strong><br />
 </p><br />
<p class='bbc_left'>We can improve two aspects of the graph on Figure 15. Namely, both location and radius of nodes of dual graph can be picked more advantageously. Placing dual graph node at the incenter of the triangle (center of inscribed circle) and setting its radius to the radius of inscribed circle will give a better version of the graph (see Figure 16).<br />
<br />
Note that overlapping nodes are not presenting a problem as any path inside a node radius is a valid path. Larger radius of the dual graph nodes would allow the agent to switch to the next node when following a path that includes dual graph node. Presence of the nodes corresponding to the vertices of the triangulated navigable area ensures that there will be no shortcuts across blocked areas due to too large dual nodes.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3720-0-93124900-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3720" title="Fig16.png - Size: 33.48K, Downloads: 204"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-76642600-1309294292_thumb.png" id='ipb-attach-img-3720-0-93124900-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig16.png" /></a><br />
<strong class='bbc'>Figure 16 Placement of dual graph vertices at the incenter of triangle.<br />
Radius of dual nodes set to the radius of the inscribed circle.</strong><br />
 </p><br />
<p class='bbc_left'>The graph shown on the Figure 16 may still present challenges in run-time: consider an agent starting path near the left-most bottom node of the graph and going into any other room. It would find the nearest node (left bottom node) and initially move towards it, and only after reaching it within the radius of the node the agent would turn to follow the path. This will present an obviously undesirable backtracking.<br />
<br />
There are few approaches to this problem. One is to remove such redundant nodes (as obviously the graph will serve its purpose without corner nodes). But that will only make the problem slightly less obvious as there will be similar arrangements of nearest node and initial position leading to backtracking.<br />
<br />
Another possible solution can be implemented in run time. After the path is calculated, we can check if the agent can start the path from Nth > 1 node by skipping the first few nodes. This will make pathfinding somewhat more expensive as we would need to run ray intersection tests against blocking primitives to ensure that shortcut is acceptable. On the other hand we would still need to do some path “beautification” to make it less robotic so this additional check may be not so expensive in comparison to other calculations we would need to perform.<br />
<br />
In concluding this section we can tell that there are more ways to improve the graph on Figure 16, e.g. by reducing number of edges (redundant edges may result in slower run time performance of A*), better placement of nodes, etc. However the graph as we built it will perform reasonably well. Also it could be easily modified by level designers manually, if necessary, to meet their specific needs not covered by automatic graph generation.<br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Hierarchical graphs </span></strong><br />
<br />
Hierarchical navigation graphs come in handy when dealing with large environments with relatively loosely connected regions. In indoors environment, such connection is usually done via portals. Building "super-graph" with nodes corresponding to regions and edges to portals may greatly reduce load on A* when navigating between distant regions of the environment.<br />
<br />
Indeed, first we can identify the super-node corresponding to the region where the agent is located and the super-node for the destination region. An A* run on super graph can return either "no path" if the regions are not connected, or a navigable path in super graph. This path consists of a list of regions the agent needs to visit in order to reach its destination. Navigation within each region is handled by a-star on regular graph.<br />
<br />
Such optimization can be extremely helpful in particular in the cases when no path exists. Super-graph is much smaller and the absence of the path, if it happened to be the case, is learned at a much lower cost than exhaustive search on the regular navigation graph. This observation may seem not so important at the first glance but in practice most spikes in the navigation performance are usually coming from A* failing to find the path on a large graph.<br />
<br />
Similar optimization is possible when we deal with open terrain and the regions are not so loosely connected. Still super graph would correctly reflect connectivity information on larger scale thus we can avoid expensive searches with negative outcome.<br />
 </p><br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[ef9dc63cf8b7278c51e4b067c7e6c3af]' id='ipb-attach-url-3721-0-93142600-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3721" title="Fig17a.png - Size: 17.18K, Downloads: 170"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-41552200-1309294293_thumb.png" id='ipb-attach-img-3721-0-93142600-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig17a.png" /></a> <a class='resized_img' rel='lightbox[]' id='ipb-attach-url-3703-0-92822800-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3703" title="Fig03.png - Size: 32.96K, Downloads: 330"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-37259600-1309294269_thumb.png" id='ipb-attach-img-3703-0-92822800-1330207784' style='width:178;height:200' class='attach' width="178" height="200" alt="Attached Image: Fig03.png" /></a><br />
<strong class='bbc'>Figure 17 First super-level of navigation graph (left) of the graph on the<br />
right.</strong><br />
 </p><br />
<p class='bbc_left'>Super nodes of the next level of the hierarchy of the navigation graph don’t have to be placed at specific locations. But they are in logical correspondence to the regions they represent. The portal nodes (smaller blue nodes) also have to be in one-to-one correspondence of the portal nodes of the base navigation graph. Note that regions on the right are connected with single edge. This simplifies structure of the super-graph. Super graph still has to provide functionality to estimate distances to allow A* heuristics work efficiently.<br />
<br />
Partitioning of the level into regions corresponding to the nodes of super graph has additional benefits. One of them is that we can worry less about situations like on Figure 4 when the nearest node is picked across blocked terrain. If the search for nearest node is limited to the current region then such situations will happen much less often and the search itself will speed up.<br />
<br />
Apparently two-level hierarchy can be generalized to more levels but this is rarely justified in practice.  <br />
<br />
It is possible to come up with an automatic procedure to build a super graph from the original navigation graph but it is also often done manually. Hierarchical graphs are natural notion for graph-based navigation and reuse most of the code of the underlying a-star-based framework. Thus adding and supporting super graph can be quite easy and straightforward while performance advantages can be really dramatic. This may be a strong argument in favor of choosing graph-based approach for many types of environments.  <br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Conclusion </span></strong><br />
<br />
In this article we focused on navigation graphs as a still-frequent solution to represent navigation data for games. The discussion covered several topics related to creation of navigation graphs for game environments based on different representation of navigable geometry in the game. Each stage of navigation graph creation contains a number of problems with deep roots in computational geometry. As we showed, insights from image processing can also benefit navigation graph creation.<br />
<br />
While presented material is not sufficient to build a complete system, by far, it exposes some of the interesting aspects of the process and provides pointers to further research to those who are not relying on middle-ware for their routing needs.<br />
<br />
Some of the approaches discussed here were applied to one of the projects the author worked in the past. Those approaches proved to be practical enough, not just of academic interest. Also the belief is that there are many more interesting topics in the area of navigation graph generation that can benefit game developers who are adventurous enough to go after custom solutions for their navigation needs.<br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>References </span></strong><br />
<br />
[Botana2010] César Botana “<em class='bbc'>Electric Eye: Pattern Recognition in Augmented Reality</em>”, Game Developer Magazine, December 2010, pp.22-25<br />
<br />
[Bradski2008] Garry Bradski, Adrian Kaehler “Learning OpenCV: Computer Vision with the OpenCV library” O’Reilly 2008, 555 pages<br />
<br />
[deBerg2010] Mark de Berg et al, Computational Geometry: Algorithms and Applications, 3d edition, Springer, 2010, 386 pages.<br />
<br />
[Matthews2002] James Matthews "Basic A* Pathfinding Made Simple" AI Game Programming Wisdom, Charles River Media 2002, pp. 105-103<br />
<br />
[Snook2000] Greg Snook “<em class='bbc'>Simplified 3D Movement and Pathfinding Using Navigation Meshes</em>”  in Game Programming Gems, Charles River Media, editor Mark DeLoura, 2000, pp. 288-304<br />
<br />
[Stout2000] Bryan Stout “<em class='bbc'>The Basics of A* for Path Planning</em>”  in Game Programming Gems, Charles River Media, editor Mark DeLoura, 2000, pp. 254-263<br />
<br />
[OCV] OpenCV, an open source computer vision library available from SourceForge <a href='http://sourceforge.net/projects/opencvlibrary/files/opencv-win/2.2/' class='bbc_url' title='External link' rel='nofollow external'>http://sourceforge.n...opencv-win/2.2/</a><br />
<br />
[Orourke2000] J. O'Rourke “<em class='bbc'>Computational Geometry in C</em>“ Cambridge University Press; 2000, 390 pages<br />
<br />
[Seidel1988] R. Seidel. “<em class='bbc'>Constrained Delaunay Triangulations and Voronoi Diagrams with Obstacles</em>.“ Technical Report 260, Inst. for Information Processing, Graz, Austria, 1988</p>]]></description>
		<pubDate>Tue, 28 Jun 2011 21:28:28 +0000</pubDate>
		<guid isPermaLink="false">b82b80956cfbe75101bd223fe6319dec</guid>
	</item>
	<item>
		<title>The Core Mechanics of Influence Mapping</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/the-core-mechanics-of-influence-mapping-r2799</link>
		<description><![CDATA[<em class='bbc'>[This tutorial and its accompanying video (on the last page) were produced by Alex J. Champandard, Technical Director at <a href='http://aigamedev.com/' class='bbc_url' title='External link' rel='nofollow external'>AiGameDev.com</a>.  If you'd like to find out more about game AI, don't miss his free <a href='http://aigamedev.com/events/' class='bbc_url' title='External link' rel='nofollow external'>interviews and masterclasses</a> (almost) every weekend!].</em><br />
<br />
Influence maps have been around since the very early days of game AI,  tracing their history back to real-time strategy games over a decade  ago.  Since then, influence maps have become a cornerstone technique for  game developers, and are even starting to become prevalent in  first-person shooters as well (e.g. KILLZONE 2/3).<br />
<br />
  In this tutorial, you'll learn about some of the motivation for  influence maps and why they are so appealing.  You'll also find out when  to use influence maps, and what representation fits best with your  game.  Then, you'll see the algorithm in action as well as its most  important parameters that you'll need to tune when using influence maps  in your game.<br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Motivation</span></strong><br />
<br />
  Influence maps ultimately help your AI make better decisions by  providing useful information about the world.  In particular, influence  maps provide three different types of information that are particularly  useful for decision making:<ul class='bbc'><br /><li><strong class='bbc'>Situation Summary</strong> — Influence maps do a great job of  summarizing all the little details in the world and making them easy to  understand at a glance.  Who's in control of what area?  Where are the  borders between the territories?  How much enemy presence is there in  each area?<br /></li><li><strong class='bbc'>Historical Statistics</strong> — Beyond just storing information about  the current situation, influence maps can also remember what happened  for a certain period of time.  Was this area being assaulted?  How well  did my previous attack go?<br /></li><li><strong class='bbc'>Future Predictions</strong> — An often ignored aspect of influence  maps, they can also help predict the future.  Using the map of the  terrain, you can figure out where an enemy would go and how his  influence would extend in the future.<br /></li></ul><br />
  As you can imagine, each of these different properties of influence  maps helps the AI perform its threat analysis calculations in a much  more intelligent way.  Since these are factors that we take into account  as human players, it should also help the AI!<br />
<br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2932-0-98105000-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2932" title="IM_Motivation.huge.png - Size: 1.4MB, Downloads: 2693"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-24934000-1307584294_thumb.png" id='ipb-attach-img-2932-0-98105000-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_Motivation.huge.png" /></a><br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Why Not Influence Maps?</span></strong><br />
<br />
  If you're already convinced about the benefits of influence maps, you  should probably take a second to pause before implementing them.   There's one reason that you wouldn't really need them in your game; if  the world is too simple you just don't need a "map" for it.  This is the  case for large open terrains with the occasional tree, for example.<br />
<br />
  In general, you need an influence map in the following cases:  <ul class='bbcol decimal'><br /><li>If your graph has <strong class='bbc'>varying connectivity</strong>, and not just a 2D grid with all its connections traversable.<br /></li><li>If your world has <strong class='bbc'>interesting features</strong> like choke-points, large open areas, large obstacles.<br /></li></ul><br />
  Otherwise, you can use simple distance-based equations in your AI  decision making to reason about the world.  There's no need for the  overhead of an influence map in memory, nor its computational cost.<br />
<br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2933-0-98119200-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2933" title="IM_Terrain.huge.png - Size: 803.44K, Downloads: 2644"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-05488500-1307584360_thumb.png" id='ipb-attach-img-2933-0-98119200-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_Terrain.huge.png" /></a><br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Representation</span></strong><br />
<br />
  High-precision grids, rough area graphs, waypoint networks, or a  coarse grid in space; all are sensible options for representing an  influence map.  There are more options too!  Generally there are two  things you need from your influence map representation:  <ul class='bbc'><br /><li><strong class='bbc'>Spatial Partition</strong> — A way to easily and efficiently partition  space and store information (i.e. influence) for each partition.  This  allows the influence map to store information about the past, gathering  statistics about what happened.<br /></li><li><strong class='bbc'>Connectivity</strong> (optional) — An indication of connectivity  between these spatial partitions in space.  The connections allow the  influence mapping algorithm to predict how influence could spread  through the level, predicting what could happen in the future.<br /></li></ul><br />
  Obviously, the important question is which is the best choice for  your game?  Generally, the more precise representations will be useful  for low-level decision making, and larger partitions will be better  suited to high-level decision making.<br />
  <br />
<strong class='bbc'><span style='font-size: 12px;'>a) 2D Grids</span></strong><br />
<br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2934-0-98131700-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2934" title="IM_2DGrid.huge.png - Size: 988.75K, Downloads: 1665"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-88114700-1307584435_thumb.png" id='ipb-attach-img-2934-0-98131700-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_2DGrid.huge.png" /></a><br />
<br />
This is a great default representation if you can map your world to a  mostly 2D environment.  It's a very fast representation to process and  very simple to implement.  The downsides, however, are that you may  waste memory if you have sparse environments.<br />
<br />
<strong class='bbc'><span style='font-size: 12px;'>b) Area Graphs</span></strong><br />
<br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2935-0-98143500-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2935" title="IM_AreaGraph.huge.png - Size: 649.07K, Downloads: 1438"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-25215100-1307584506_thumb.png" id='ipb-attach-img-2935-0-98143500-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_AreaGraph.huge.png" /></a><br />
<br />
If you have a navigation hierarchy in place already, then you can use  that as the basic representation for the influence map.  The advantage  of this approach is that it's not a very intrusive change and can easily  be incorporated into most game engines.  The disadvantages are the lack  of precision in cases where details are required for the decision  making.<br />
<br />
<strong class='bbc'><span style='font-size: 12px;'>c) Waypoint Network</span></strong><br />
<br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2936-0-98155700-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2936" title="IM_WaypointNetwork.huge.png - Size: 708.13K, Downloads: 1248"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-06247600-1307584544_thumb.png" id='ipb-attach-img-2936-0-98155700-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_WaypointNetwork.huge.png" /></a><br />
<br />
Using a full waypoint network in 3D resolves some of the problems  with 2D grids, as you can easily wrap a waypoint network over multiple  levels of a building or upstairs.  However, the downside is that it's  much less efficient to process than both a grid or an area graph.<br />
<br />
<strong class='bbc'><span style='font-size: 12px;'>d) Coarse Grid</span></strong><br />
<br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2938-0-98167600-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2938" title="IM_CoarseGrid.huge.png - Size: 894.44K, Downloads: 1129"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-73826600-1307584599_thumb.png" id='ipb-attach-img-2938-0-98167600-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_CoarseGrid.huge.png" /></a><br />
<br />
One last option is to decrease the resolution of the grid.   Unfortunately, this causes certain grid cells to span over obstacles,  which can cause problems when updating the influence.  The alternative  is to remove those split cells from the representation, but certain  connectivity may be lost because of it.  Using these cells as  disconnected buckets in space to store influence is also an option,  though it rules out predicting the spread of the influence in the  future.<br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>The Algorithm </span></strong><br />
<br />
Fundamentally, the algorithm is similar to a blurring process that you  can find in photo editing software like Photoshop.  You start by  setting the influence values in your map, and then repeatedly blur the  map to spread the influence from the source towards neighboring nodes.<br />
<br />
  The influence mapping algorithm is actually pretty flexible.  It's  made up of two different steps, but you can run those steps in any order  you see fit and customize them quite extensively.<br />
  <br />
<strong class='bbc'><span style='font-size: 12px;'>1) Setting Influence</span></strong><br />
<br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2939-0-98181100-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2939" title="IM_SettingInfluence.huge.png - Size: 972.43K, Downloads: 1127"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-45942500-1307584671_thumb.png" id='ipb-attach-img-2939-0-98181100-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_SettingInfluence.huge.png" /></a><br />
<br />
Typically, the first step is to set the influence sources inside the  representation you chose.  It's as easy as storing or updating a  floating point number in an array of influence values.  The only  challenge is figuring out the influence sources for your game.  Often  these sources can be:  <ul class='bbc'><br /><li>Entities, both friendly and enemy soldiers, semi-permanent turrets, etc.<br /></li><li>Events like grenade explosions, bullet fire, taking damage.<br /></li></ul><br />
  You'll also need to figure out which of these influence sources are  additive (layered on top of the existing influence) and which are  reference (set as the base influence value).  That depends on your game,  but temporary events like bullet fire are well suited to additive  influence.<br />
<br />
<strong class='bbc'><span style='font-size: 12px;'>2) Propagation</span></strong><br />
<br />
  The propagation algorithm itself is very simple, and fits in less  than a page of code.  There are many different ways you can implement  this, and many variations would also work fine... but this is a good  place to start:<br />
<br />
<pre class='prettyprint'>void InfluenceMap::propagateInfluence()<br />{<br />  for (size_t i = 0; i &lt; m_pAreaGraph-&gt;getSize(); ++i)<br />  {<br />	float maxInf = 0.0f;<br />	Connections& connections = m_pAreaGraph-&gt;getEdgeIndices(i);<br />	for (Connections::const_iterator it = connections.begin();<br />		it != connections.end(); ++it)<br />	{<br />	  const AreaConnection& c = m_pAreaGraph-&gt;getEdge(*it);<br />	  float inf = m_Influences&#91;c.neighbor&#93; * expf(-c.dist * m_fDecay);<br />	  maxInf = std::max(inf, maxInf);<br />	}<br /><br />	m_Influences&#91;i&#93; = lerp(m_Influences&#91;i&#93;, maxInf, m_fMomentum);<br />  }<br />}</pre><br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2940-0-98193300-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2940" title="IM_Propagation.medium.jpg - Size: 53.76K, Downloads: 1046"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-81693000-1307584788_thumb.jpg" id='ipb-attach-img-2940-0-98193300-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_Propagation.medium.jpg" /></a><br />
<br />
A few things to note:  <ul class='bbcol decimal'><br /><li>You need double buffering if you want your influences to be  calculated correctly.  You can do that by setting the new influence  values in a local store, then copying it back into the m_Influences  array.  If you do an extra propagation step each frame, then you can  avoid the copy (at the cost of some extra processing).<br /></li><li>Without double buffering, the influence may propagate differently  depending on the order of your graph nodes and how you process them.   This makes the influence on a grid look a bit more irregular, but  nothing fatal!  If you're looking for some extra performance this may  help a bit in practice.<br /></li><li>Here the code uses exponential decay for the influence, which has  some nice properties.  However, it's a bit slower than linear decay for  instance, which only requires a division and not an exponential  function.<br /></li><li>The code above only handles positive influences and their  propagation.  If you need to handle negative influences also, then you  could also accumulate the minimum influence and combine them together.<br /></li></ul><br />
<strong class='bbc'><span style='font-size: 18px;'>Parameters </span></strong><br />
<br />
The only challenge left is figuring out the parameters for the code  snippet above.  Here's a breakdown of the most important ones you need  to keep in mind.<br />
  <br />
<strong class='bbc'><span style='font-size: 12px;'>a) Momentum</span></strong><br />
<br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2941-0-98205100-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2941" title="IM_Momentum.huge.png - Size: 1.29MB, Downloads: 923"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-71495500-1307584844_thumb.png" id='ipb-attach-img-2941-0-98205100-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_Momentum.huge.png" /></a><br />
<br />
When you update the influence value, how much do you bias the update  towards the existing value compared to the new value?  The code above  uses linear interpolation to blend from the current value to the new  value, and then relies on the momentum parameter to control the result.<br />
<br />
   If you set the momentum to high (closer to 1.0) then the algorithm  will bias towards the historical values of the influence, which is  particularly well suited to storing statistics about previous attacks.   Use this for things like high-level strategic maps.  Conversely, if you  set the momentum parameter to low (closer to 0.0) then the algorithm  biases towards the currently calculated influence, so the propagation  happens quicker and the prediction is more accurate.  Use this for  low-level influence maps for individual positioning for example.<br />
<br />
<strong class='bbc'><span style='font-size: 12px;'>b) Decay</span></strong><br />
<br />
  How quickly should the influence decay with distance?  In the code  snippet above, this is controlled by a multiplier to the distance before  it's passed to the exponential function, so you can control how quickly  the influence fades.<br />
<br />
  Typically, you'll use different decay values based on the size of  your influence map.  Lower decay for larger strategic maps, and higher  decay when the map is localized and used for tactical purposes.  If  you'd like influence to spread differently per-unit then most likely  you'll need different influence maps for that, or a customized algorithm  that stores additional information per cell.<br />
<br />
<strong class='bbc'><span style='font-size: 12px;'>c) Update Frequency</span></strong><br />
<br />
  The parameter you'll have the least control over, is the update  frequency.  This will depend on how many resources you have at your  disposal for updating the AI.  Luckily, influence maps can scale down  relatively well, but there's a base amount of computation that needs to  be done to get good quality information.<br />
<br />
  Most often, you'll update high-level strategic maps less often, for  example at 0.5Hz to 1Hz.  Then, at the low-level for the tactical maps  that individuals use, consider doing that at 2Hz to 5Hz.  No influence  maps really need to be updated at 30 FPS!<br />
<br />
<a class='resized_img' rel='lightbox[33935382f94a97306797331c74955428]' id='ipb-attach-url-2942-0-98216900-1330207784' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2942" title="IM_UpdateFrequency.huge.png - Size: 835.06K, Downloads: 643"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-05148500-1307584884_thumb.png" id='ipb-attach-img-2942-0-98216900-1330207784' style='width:250;height:141' class='attach' width="250" height="141" alt="Attached Image: IM_UpdateFrequency.huge.png" /></a><br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Tutorial Video</span></strong><br />
<br />
<iframe src="http://player.vimeo.com/video/23913640" width="400" height="250" frameborder="0"></iframe><br />
<br />
<strong class='bbc'><span style='font-size: 18px;'>Conclusion </span></strong><ul class='bbcol decimal'><br /><li>Influence maps are particularly easy to get up-and-running!  It's less than a page of code.<br /></li><li>You'll most likely end up with a variety of different influence maps to provide better information to your AI.<br /></li><li>Pick your map representations wisely, though a 2D grid and your existing area graph are the safest bets.<br /></li><li>Expect a lot of iteration along with the AI decision making as you tweak the parameters of your influence map.<br /></li></ul><br />
  If you have any questions on the topic of influence maps and their  use for spatial decision making, don't hesitate to ask here or via <a href='http://twitter.com/AiGameDev' class='bbc_url' title='External link' rel='nofollow external'>Twitter</a>!]]></description>
		<pubDate>Thu, 09 Jun 2011 02:04:51 +0000</pubDate>
		<guid isPermaLink="false">3d65824c0a13e8417758ea807a431500</guid>
	</item>
	<item>
		<title>AIGameDev</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/aigamedev-r2442</link>
		<description></description>
		<pubDate>Tue, 11 Dec 2007 08:22:26 +0000</pubDate>
		<guid isPermaLink="false">52156f7194073f084237a48a1c2b7ea4</guid>
	</item>
	<item>
		<title>Pathfinding With the C4 Game Engine</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/pathfinding-with-the-c4-game-engine-r2420</link>
		<description><![CDATA[

<h1>Introduction</h1>
<p class="par">The <a href="http://www.terathon.com/">C4 game engine</a> has to be one of the best kept secrets in the independent gaming community. It has been in development by the principal
developer, Eric Lengyel, for several years. It supports many advanced features such as real-time dynamic shadows for any number of lights, fully calculated specular or micro-facet reflections on any
surface, and comes with a robust editor to import and prepare geometry for the game engine. It also implements a robust portal culling system, including support in the tools for building portaled
level geometry.</p>
<p class="par">Once you buy the engine for $200, you get not only free updates for the life of the engine, but also the full source code. This is quite comparable to the offering that Garage Games
has for the Torque Game Engine, but the comparison stops there. Where Torque needs long lighting compile phases, C4 just runs once you've saved your level. Where Torque code resembles a tentacle
monster, with tendrils reaching from all place to any other place, the C4 code is very modular and easy to find your way around. Where Torque exporters for packages such as 3ds Max are notoriously
finicky and crashing, C4 uses COLLADA for importing any geometry from anywhere. And where Garage Games never answers questions, Eric provides top-notch service and bug fixing through the C4 forums.
Perhaps the only reason Eric can do that is that C4 doesn't have as big a following, so it might be in my best interest to not turn you on to C4 :-)</p>
<img class="c1" src="http://images.gamedev.net/features/programming/c4pathing/navmeshshot-md.jpg" height="192" width="256">
<p class="par">C4 does miss some things that are available in some other game engines, though. It is currently mostly an indoors engine (with outdoors being next on the road map). The physics is
quite basic -- spheres and rays collided against the ground, with simple euler based physics. And, last, there is no real scripting language in C4. There are triggers, and controllers, and a visual
macro package that can run in response to triggers, but any "real" coding has to be done in C++.</p>
<p class="par">Another thing missing in C4 (and missing in TGE, too), is support for navigation and path finding for NPCs. I spent the last few evenings trying to work something out, mainly for the
challenge, and the chance to experience C4 in a little more depth. This article presents my findings, which includes source code and some advice about how to use it with the C4 engine.</p>
<p class="par">While the source code included doesn't expose any C4 code (doing so would be against the C4 license agreement), but it will use the general framework of C4 in its Locator markers and
Controller node attachments. However, you can use these same techniques implemented in this code, in some game of your own, as long as you have the same features available to you: placing markers in
the world, finding these markers, and testing whether you can move through the world along a given direction or not.</p>
<h1>Requirements</h1>
<p class="par">The requirement for this navigation system is to make it possible to plan a path, for a player character or non-player character, from point A to point B within the game world, without
too much burden on the CPU at runtime. While there are some systems that can do this entirely automatically, the system I present here is implemented based on hints given by the level artist. This
has two benefits: First, it allows the artist to express things he knows about the navigability of a level, that an automatic algorithm might not. Second, it's a lot simpler to implement!</p>
<p class="par">The implementation will construct a graph of "navpoints," where each navpoint is connected to some other navpoints in a directed graph approach. An edge in this graph from navpoint A
to navpoint B means, that if an NPC starts at point A, and aims at point B, and walks forward, he will get to point B (unless some other movable obstacle is in the way).</p>
<p class="par">There is an additional gnarl, in that the NPC will not be right on one of these navpoints when it needs navigation services, and the final destination (say, the player, or some in-game
goal) may not be right at a navpoint either. Thus, we need to be able to get to the closest navpoint from where we currently are, and we need to be able to get from the endpoint of the navigation
path to the destination location.</p>
<p class="par">So, to put it all in one place:</p>
<ul>
<li>The artist or level designer places navpoints in the level editor, to indicate generally navigable areas.</li>
<li>These navpoints are discovered during level loading, and the connectivity between them is automatically calculated.</li>
<li>Navpoint system provides a function "find the navpoint closest to point P, from which you can actually get to P."</li>
<li>Navpoint system provides a function "find the navpoint closest to point Q, such that you can get from Q to that navpoint."</li>
<li>Navpoint system provides a function "find a path along the navpoint mesh that travels from navpoint A to navpoint B."</li>
</ul>
<h1>Finding the Navpoints</h1>
<p class="par">In the C4 editor, you can place "Locator" markers. You do this by opening the Marker page, selecting the Locator tool, and clicking in the world editor. Once a Locator is placed, you
can move it around with the node movement tool, and you can do Get Info on the marker to set the Locator Type, a four-letter code that is used in the game to understand what kind of marker it is.</p>
<p class="par">In the system I implemented, the artist will place Locator markers and make them of Locator type "navi". The system will then find connections between markers on level load time. The
component that does this connection finding is a Controller. Controllers are one of the main ways of getting custom code into the C4 scene graph. Any node can have zero or one controllers assigned to
it, and the controller can expose Settings which are edited on the node in the World Editor.</p>
<p class="par">I wanted to be able to create different kinds of nav meshes, say for wheeled vehicles versus kangaroos, so I decided that each NavmeshController instance will only consider "navi"
Locators that are direct children of the controllers node. Thus, the artist will place all the locators, select them all, and Group them together. You will then add the "Navmesh" controller to that
Group node, and set pathfinding parameters (such as jump height) on that controller.</p>
<p class="par">Thus, in the NavmeshController::Preprocess() function, which is called when the level first starts up, the Navmesh finds all its children that are Locators of type "navi," and then
proceeds to test connectivity between each pair of markers. To prevent this from taking a very long time (N-squared ray casts), the artist can set a maximum distance (radius plus vertical
displacement) in the controller settings, and any pair of locators that are further away than this will not be considered as a connected pair. The connected neighbors for each navpoint are then
stored in an array. I chose one global array with a separate index table for cacheability, but I think the code would have been cleaner if I just stored one small array for each navpoint. This
connectivity array is not stored in the level file; instead it's calculated each time the level starts up. For my small test levels, that operation is so fast you can't measure it; for a really large
level, it might make sense to allow saving the calculated connectivity.</p>
<h1>Finding Navigability</h1>
<p class="par">In my first implementation, I just cast a ray from point A to point B to see whether there was anything in the way. This was great at making NPCs not walk through walls, but they would
gladly throw themselves into a lava canyon that was between two separate ledges, as long as the raycast from a navpoint on ledge A to ledge B was unimpeded.</p>
<p class="par">To improve this behavior, I first added the capability for an artist to mark, for a given navpoint, which other navpoints should NOT be considered reachable, even if the raycast says
it is. While this allows problem cases to be manually fixed, it turned out to be a cumbersome process, and because of that, very fragile in the face of change to the level geometry.</p>
<p class="par">To even be able to debug these problems, I added a command to the C4 command console which shows and hides navmeshes in the world. To be able to tell different meshes apart (meshes
that come from different NavmeshController instances, and thus different groups of "navi" locators), I added a mesh display color property to the controller. I also added some functions to re-build
the navigation mesh at runtime, and to list the general status of the navigation mesh system.</p>
<p class="par">Other problems with the generated mesh included very complex interconnectivity, where a navpoint in the corner of a room might be connected to every other navpoint in that room. While
technically correct, this creates meshes that look bad (but might play very well). To work around this issue, I added a feature in the calculation where connectivity between two navpoints will not be
considered if other connected navpoints are "closer" and in the "same general direction."</p>
<p class="par">At this point, with enough manual tweaking, and setting the global "radius" and "vertical" values according to the level, something playable could be created.</p>
<h1>Refining Navigability</h1>
<p class="par">Throwing yourself in a lava moat does not count as "intelligent" behavior for an NPC. While working around it with explicit node pair exclusion might work for a tortured artist, it
won't work when trying to solve the problem of moving from a random point P to the closest navmesh point. Thus, a better way of finding navigability over some area of level must be found.</p>
<p class="par">I decided to brute-force it. Once I know that there's not a wall between point A and point B, I walk the extent of the ray and sample the height difference along the path. If there is
a drop, it doesn't matter, as it's OK to jump off ledges. As long as the drop is not too steep! I added a parameter to the controller for what's considered too steep. Additionally, if a single step
up is too steep, the NPC won't be able to climp or jump up, so I added another parameter to the controller for what's considered too steep. Last, I added a third parameter to determine how far to
step in each iteration of finding the height profile. This will let artists make navmesh compilation a little faster on levels that don't have complex ramps, moats or other height complexity, while
allowing for a very fine-grained navigability determination on harder levels.</p>
<p class="par">The nice part of it is that this function can be used both when calculating navigability during start-up, and when trying to find the closest navmesh point that you can actually get
to.</p>
<h1>Using the Code</h1>
<p class="par">Just add the NavmeshController.cpp and NavmeshController.h files to your "Game" DLL MSVC project and build (this is typically "Game.dll" or "SimpleChar.dll" or "Skeleton.dll" depending
on how you started your game).</p>
<p class="par">In your World subclass Render() function, after calling World::Render(), you migth want to call MaybeRenderNavmeshes(). This will draw the navmeshes in wireframe, if the console
command to turn them on has been run. ("navmesh show")</p>
<p class="par">If the level designer has built one or more nav meshes, they will be automatically created when the level is loaded. To actually get ahold of one, by name of the group node containing
the controller, call GetNavmeshController("name"). If you pass NULL for name, the first navmesh (in scene graph unpacking order) will be returned; this is mostly useful when you have only one
navmesh.</p>
<p class="par">To plan a path from point A to point B, call NavmeshPathCreate(begin, end). This will do initial path planning to get to the navmesh, and will then navigate through the mesh to the
desired destination. Each step for your navigating character, you'll want to call Move(pos, &dir), passing in your current position, and getting out a desired direction to move in. Once you're
done with the navigation (either at the destination, or choosing a different goal), call Dispose() on the returned NavmeshPath.</p>
<p class="par">The NavmeshControllers will be deleted when the level is unloaded, so you do not need to separately manage their lifetime.</p>
<h1>Reading the Code</h1>
<p class="par">You can <a href="http://downloads.gamedev.net/features/programming/c4pathing/pathfinding-070824.zip">download the code</a> in an archive. Some things about the code might be worth
mentioning, though.</p>
<p class="par">First, the specific use of templates is a pattern that I use quite often, but might confuse you if you haven't seen it before. When you create a large number of objects of the same
general kind, such as settings controls in a GUI, and also wanting to marshal/demarshal data that those same controls act on (or perhaps saving/loading to file, etc), it's nice if you don't have to
update a zillion places each time you add a new member variable. To solve that problem, I use a single visitor function, that visits all the member variables, passing in various information about
each member as it's being visited. While the file saving code might not care what the title of the member should be when displayed in a GUI, it also doesn't really hurt. Thus, for each operation on
the members, a separate actor is created and passed to the visitor function. Most of those actors can actually be re-used between object implementations, so while it's a lot of code to write a single
float to a file, or create a single text edit control, it saves a lot of code in the long run. Given that I added different control parameters while moving along with the implementation, I believe
this pattern paid for itself during this development effort alone. Any new controller I write for C4 will be a pure time win -- not to mention the bugs I avoid by doing each thing only in one
place!</p>
<p class="par">Next, the implementation uses no private or protected members. This is in general a pretty bad idea, if you want to expose the implementation. However, the navmesh implementation is in
a .cpp file, so no client of the navmesh can poke at those non-private members, so in this case, it's actually a benefit. Some of you may know of this as "interface programming." Unfortunately, the
rest of C4 does not use interfaces; instead it uses concrete classes with sometimes deep inheritance, and heavy use of private members. The draw-back, as I'm sure you know, is that any change to an
implementation detail (such as the type of a member variable) will cause a re-compilation of every client of that class, even if the functional interface to the class has not changed.</p>
<p class="par">The A-star function (called NavmeshController::AStarSearchIntoWalkPath) is all one big function, but I believe it's OK to make it one function, as it keeps all the concepts in one
place for this algorithm. I will not explain A-star in depth, as there are many tutorials on that on the web, except to say that this implementation shows A-star on a generalized directed graph,
rather than just the boring old square tiles most often illustrated. Read the comments for more information!</p>
<p class="par">Finally, the versioning mechanism used in the file I/O is something you might want to pay attention to. It allows you to add new members to an existing data type, and have them persist
in newly saved files, while still correctly opening older file versions. In fact, with only a little bit of code change, you could even support writing older versions of files!</p>
<h2>The 'navmesh' console command</h2>
<p class="par">In the console, once a navmesh is instantiated, you can use the navmesh command to get some useful feedback about the navmeshes and how they do path finding. Here are some example
commands.</p>
<dt class="code">navmesh show</dt>
<pre>

</pre>
<dd>Turn on display of the navmesh for each loaded navmesh controller. The display will use the color configured on each controller for the respective meshes. The color will be bright where
connectivity from one node to another starts, and will be black at the arriving node, to help in understanding one- way connectivity.</dd>
<pre>


</pre>
<dt class="code">navmesh hide foo2</dt>
<pre>

</pre>
<dd>Turn off display of the navmesh for any controller that is attached to a group node that has a name that contains "foo2" as a substring.</dd>
<pre>


</pre>
<dt class="code">navmesh path 4,1,2 -5,-3,2</dt>
<pre>

</pre>
<dd>Using the first navmesh found in the level, find a path from the location (4,1,2) to the location (-5,-3,2). Display that path in white. If no path can be found, print an error to the
console.</dd>
<pre>


</pre>
<dt class="code">navmesh path clear</dt>
<pre>

</pre>
<dd>Clear all the displayed paths. Currently, this flavor of the command does not take an optional navmesh name substring identifier -- it always clears all navmesh paths.</dd>
<pre>


</pre>
<dt class="code">navmesh</dt>
<pre>

</pre>
<dd>Display the name and status of all loaded navmeshes.</dd>
<pre>

</pre>
<h1>Final notes</h1>
<p class="par">I release the pathfinding code under the MIT license, which basically means that you're free to use it for any purpose, as long as my copyright is retained, and as long as you
indemnify and hold harmless me for any damage resulting out of your such use, because I claim no merchantability or fitness for a particular purpose of the code.</p>
<p class="par">I would like to thank Eric Lengyel for writing the C4 engine. I would like to thank the community at the C4 message boards for feedback on the initial implementation and this article.
I would like to apologize to my wife, as I've been all grumpy sitting up until the middle of the night writing this code and article. And don't forget to <a href=
"http://downloads.gamedev.net/features/programming/c4pathing/pathfinding-070824.zip">download the code</a>!</p>
<p class="par">Thanks for reading.</p>

]]></description>
		<pubDate>Wed, 10 Oct 2007 03:37:02 +0000</pubDate>
		<guid isPermaLink="false">2b8f7198614e3d872116d3c2840fd37c</guid>
	</item>
	<item>
		<title>Design Pattern: Variant</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/design-pattern-variant-r2029</link>
		<description><![CDATA[Design Pattern: Variant<br />
Copyright © <a href='mailto:tanstaafl@gamedev.net' title='E-mail Link' class='bbc_email'>Ernest S. Pazera</a><br />
<br />
 Copyright © Ernest S. Pazera<br />
<br />
 Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included here.<br />
<br />
 <br />
<strong class='bbc'>The Issue</strong><br />
 I have a class that handles messages, based in part on the "Chain of Responsibility" design pattern. A very watered down possible implementation for my message handler class would look something like this:<br />
<br />
  class IMessageHandler { private:   IMessageHandler* m_pmhParent; protected:   virtual bool OnMessage(int iMessageID,void* pvMessageParms){return(false);} public:   CMessageHandler(IMessageHandler* pmhParent):m_pmhParent(pmhParent){}   ~CMessageHandler(){SetParent(0);}      void SetParent(IMessageHandler* pmhParent){m_pmhParent=pmhParent;}   IMessageHandler* GetParent(){return(m_pmhParent);}   bool HasParent(){return(GetParent()!=0);}   bool HandleMessage(int iMessageID,void* pvMessageParms) 	{   	if(OnMessage(iMessageID,pvMessageParms))          return(true);   	else if(HasParent())     	return(GetParent()->HandleMessage(iMessageID,pvMessageParms));   	else     	return(false); 	} };  As you can see, IMessageHandler has a single member, called m_pmhParent. This stores a pointer to the message handler's parent. If m_pmhParent is 0(i.e. a null pointer), then the message handler is said to have no parent, and would be at the root of the tree. There is, of course, no limitation to the number of message handlers that can call another message handler its parent. In fact, at least in this implementation, there is no limitation restricting a message handler from being its own parent (but this could be simply fixed in the SetParent function, so for now ignore it). SetParent and GetParent are obviously a way of managing the assignments of parents to message handlers. The HasParent function is a shorthand to keep us from having to write if(GetParent()!=0) all the time. The constructor sets up a message handler with an initial value for its parent, and the destructor eliminates that value, resetting the parent pointer to 0 (not that it really matters in this implementation).<br />
<br />
 The interesting functions are OnMessage and HandleMessage. Since OnMessage is virtual (and protected so that it cannot be called directly), we can assume that it is meant to be overridden in derived classes. This implementation simply returns false, as IMessageHandler knows nothing about how to handle any sort of message whatsoever. In another implementation, this function should perhaps be made pure virtual, as IMessageHandler itself should not be instantiated as it does nothing useful.<br />
<br />
 HandleMessage is where the "glue" between message handlers lies. It first tries to handle the message with its own OnMessage function. Failing that, it checks for a parent. If a parent exists, it passes the message on down to the parent, who repeats the process until the message is handled or the top of the chain is reached and the message is still unhandled, in which case false is returned.<br />
<br />
 Thus far, this solution is the best that I have found for basing my applications on. My application object is a subclass of IMessageHandler, as are various types of event handlers (this concept is often represented by a window), and I have also used it for finite state machines and its component states, custom user interfaces, and so on. Typically I go with a richer set of operations, like child management, but on some platforms, IMessageHandler has looked almost exactly like the implementation I have here.<br />
<br />
 So, what exactly is the problem? My main issue is the parameter list for HandleMessage and OnMessage. Both take an int (which identifies the type of message being sent), and a void pointer, which is the most generic way I could come up with to send a variable amount of data that I could cope with. I could have gone the "…" route with these functions, but I try my best to stay away from "…", as it is even more difficult to manage than a void pointer parameter, at least in my opinion.<br />
<br />
 Even with the int and void*, there are huge problems that crop up:<br />
<br />
 Problem #1: the int parameter, iMessageID, is the parameter used to differentiate types of messages. How, then, shall we ensure that our applications do not duplicate message ids, since these must be unique? Often, when defining derived classes of IMessageHandler, we will be assigning values to message ids that will wind up hidden in the implementation. If, for example, we create a custom UI and create a CButton class to represent a command button, we will naturally want a message id reserved for clicking a button. As a developer, I don't really care what the values are for a particular message id, and I really shouldn't have to care. I simply want to use some sort of identifier to send and check for messages.<br />
<br />
 Problem #2: a void* parameter is a poor way to store a variable number of parameters, especially in a strongly typed language like C++. It approaches being as bad as using "…". Many types of messages will have no parameters at all, which makes the parameter a waste. A quit message sent to an application needs no additional data. If we were simply concerned about overrunning the data buffer, we could add a size_t parameter that specifies how large the data being sent is, but that just compounds the useless parameter issue.<br />
<br />
 <br />
<strong class='bbc'>Solution?</strong><br />
 The requirements here can be broken down into the following:<br />
<br />
 Requirement #1: Messages should be represented by a fixed number of parameters, and as few as possible, without ever having wasted parameters.<br />
Requirement #2: We should avoid "…" and void* at all costs for passing information.<br />
Requirement #3: The developer should not have to know anything about the values assigned to various message identifiers, and simply used them by identifier.<br />
Requirement #4: Message identifiers should not clash.<br />
Requirement #5: Messages must be able to convey any amount of data.<br />
<br />
 To meet requirement #1, we shall limit the number of parameters to just one, so it is becoming obvious that we shall be creating a message class of some sort, which we shall pass either by pointer or reference, but we won't lock ourselves down to one or the other yet. We will need a base class for all other types of messages, which I will call MGeneric (M standing for Message), and so HandleMessage and OnMessage shall either be passed a MGeneric* or an MGeneric&.<br />
<br />
 While taking care of requirement #1, we have fulfilled requirement #2 (since we shall have a sole parameter of type MGeneric* or MGeneric&, we naturally shall not have a parameter of type void* nor a "…") and requirement #5 (through inheritance, MGeneric can be subclassed to represent any amount of data we wish).<br />
<br />
 However, this leads to the question of how exactly we will access the extended data from derived classes. Naturally, this will have to occur through some sort of casting. Typically, I make use of dynamic_cast for this, and because of this choice, I favor MGeneric* over MGeneric& as the parameter type (since a failed dynamic_cast of a pointer returns the a null pointer, whereas with a reference, a bad_cast exception is thrown-so pointers are easier).<br />
<br />
 So, here's a simple implementation for MGeneric:<br />
<br />
  typedef unsigned long messageid_t; class MGeneric { private:   messageid_t m_messageid; protected:   void SetMessageID(messageid_t messageid){m_messageid=messageid;} public:   MGeneric(messageid_t messageid):m_messageid(messageid){}   ~MGeneric(){}   messageid_t GetMessageID(){return(m_messageid);} };  Within MGeneric is the minimal amount of functionality needed to represent a message, namely the identifier (a messageid_t value, which is just an alias for unsigned long, a type sufficiently large enough for most purposes, but your mileage may vary). The SetMessageID member function is protected, so that only friends and derived classes may access it (for encapsulation purposes). GetMessageID is public, and will typically be the first value checked in an IMessageHandler::OnMessage function, usually in a chain of if/else if blocks.<br />
<br />
 Now we need to modify IMessageHandler::HandleMessage and IMessageHandler::OnMessage like so:<br />
<br />
  bool IMessageHandler::HandleMessage(MGeneric* pMessage,bool bDelete=true) {   bool bResult=false;   if(pMessage!=0)   { 	if(OnMessage(pMessage))   	bResult=true; 	else if(HasParent())   	bResult=GetParent()->HandleMessage(pMessage,false); 	if(bDelete)        delete pMessage;   }   return(bResult); }  This function is now made a little more complicated by the fact that pMessage is an MGeneric*, so we have to cleanly handle null pointer values, and since the pointer is likely going to be dynamically allocated within a function call, we have to do some garbage collection (hence the bDelete parameter).<br />
<br />
 Yes, I know I made a big to-do about useless parameters, but this one isn't useless, I guarantee you. For example, consider the following. Would you rather write code like this:<br />
<br />
  pHandler->HandleMessage(new MGeneric(0));  -OR-<br />
<br />
  MGeneric message(0); pHandler->HandleMessage(&message);  Sending a message, any message, is logically a single action, and single actions should take place on a single statement, which the first option gives you, and the second does not. There is nothing really wrong with either approach, I just prefer the former, which means I need a bDelete parameter.<br />
<br />
 The OnMessage function remains nearly the same(still virtual, still protected):<br />
<br />
  bool IMessageHandler::OnMessage(MGeneric* pMessage) {   return(false); }  The only change was the parameter list. It now has but one parameter, an MGeneric*.<br />
<br />
 So we've got three of the five requirements out of the way, we still need a way of assigning unique messageid_t values, and a way to keep them hidden from the user. I do it with a class that makes use of the factory patter and singleton pattern. I call the class FMessageID:<br />
<br />
  class FMessageID { private:   static messageid_t s_messageid_next=0;   static bool s_check_overflow=false; public:   static messageid_t Next()   { 	if(s_check_overflow) 	{   	if(s_messageid_next==0)   	{     	//overflow!   	} 	} 	else 	{   	s_check_overflow=true;   	} 	return(s_messageid_next++);   } };  Each time the user calls FMessageID::Next(), he gets a new number, starting with 0. If, for whatever reason, it gets back around to 0 again, then an overflow occurs (typically accompanied by some sort of exception being thrown). This is taken care of my the s_check_overflow variable, which skips the overflow check only once… when 0 is first being assigned.<br />
<br />
 As for how we start to attach these messageid_t values to classes, we just add them as static members to the classes that they pertain to. For example, if we created a subclass of IMessageHandler called IApplication, and wanted to associate a messageid_t with a quit message, this is how we would go about it (ignoring all of the OTHER stuff that would go into an application class):<br />
<br />
  class IApplication: public IMessageHandler { private:   static messageid_t s_MSGID_Quit=FMessageID::Next(); public:   static messageid_t MSGID_Quit(){return(s_MSGID_Quit);} };  We make the actual variable private, so that it cannot be interfered with accidentally, and then access the value from the static member function MSGID_Quit, making it a read-only property very effectively.<br />
<br />
 As for what the actual value of IApplication::s_MSGID_Quit, I have no idea, and more importantly, I don't care. It could be 0, it could be 500, and it doesn't really matter. As long as it is uniquely identified by a call to IApplication::MSGID_Quit(), I'm happy.<br />
<br />
 <br />
<strong class='bbc'>Other Uses</strong><br />
 Truth be told, the solution I have presented here was not originally implemented for messages. It was developed as a solution for exception classes. The solution looks rather a lot like MGeneric and FMessageID(so I'll spare you the code, and just fill in what is different), with the corresponding classes being EGeneric and FErrorID and errorid_t is used instead of messageid_t. In addition, EGeneric contains an additional member of type std::string that contains a textual description of the exception. For most exceptions, a simple error id and a string is all that is needed, but of course inheritance can extend them.<br />
<br />
 Additional uses I have found for this pattern are useful in AI. Imagine a generic action class called AGeneric, with actionid_t values (assigned, of course, by the FActionID class) such as AXNID_North, AXNID_South and so on. Also imagine a generic goal class, GGeneric, with goalid_t values assigned by the FGoalID class, representing both types of goals (like GOALID_Kill), priorities of goals, and extended information about the goal (like who to kill). Goals can then be placed into priority queues, and used to decide on a sequence of actions.<br />
<br />
 <br />
<strong class='bbc'>Conclusion</strong><br />
 In my lexicon of design patterns, the one that comes closest to doing what this one does is Command, but I sort of think of it as being called "Variant". I have found it to be a useful pattern, and I imagine others would as well, and so I'm sharing it.<br />
<br />
]]></description>
		<pubDate>Wed, 24 Dec 2003 19:18:20 +0000</pubDate>
		<guid isPermaLink="false">e6d71413617dfba7a5ff5b9a7180c007</guid>
	</item>
	<item>
		<title>A* Pathfinding for Beginners</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/a-pathfinding-for-beginners-r2003</link>
		<description><![CDATA[Updated July 18, 2005<br />
<br />
 This article has been translated into <a href='http://www.policyalmanac.org/games/aStarTutorial_al.pdf' class='bbc_url' title='External link' rel='nofollow external'>Albanian</a>, <a href='http://blog.vckbase.com/panic/archive/2005/03/20/3778.html' class='bbc_url' title='External link' rel='nofollow external'>Chinese</a>, <a href='http://blog.lalex.com/archives/200309/49-traduction-article-sur-pathfinding.html' class='bbc_url' title='External link' rel='nofollow external'>French</a>, <a href='http://www.policyalmanac.org/games/aStarTutorial_de.html' class='bbc_url' title='External link' rel='nofollow external'>German</a>, <a href='http://www.policyalmanac.org/games/aStarTutorial_port.htm' class='bbc_url' title='External link' rel='nofollow external'>Portuguese</a>, <a href='http://www.policyalmanac.org/games/aStarTutorial_rus.htm' class='bbc_url' title='External link' rel='nofollow external'>Russian</a>, and <a href='http://www.policyalmanac.org/games/articulo1.htm' class='bbc_url' title='External link' rel='nofollow external'>Spanish</a>. Other translations are welcome. See email address at the bottom of this article.<br />
<br />
 The A* (pronounced A-star) algorithm can be complicated for beginners. While there are many articles on the web that explain A*, most are written for people who understand the basics already. This article is for the true beginner.<br />
<br />
 This article does not try to be the definitive work on the subject. Instead it describes the fundamentals and prepares you to go out and read all of those other materials and understand what they are talking about. Links to some of the best are provided at the end of this article, under Further Reading.<br />
<br />
 Finally, this article is not program-specific. You should be able to adapt what's here to any computer language. As you might expect, however, I have included a link to a sample program at the end of this article. The sample package contains two versions: one in C++ and one in Blitz Basic. It also contains executables if you just want to see A* in action.<br />
<br />
 But we are getting ahead of ourselves. Let's start at the beginning ...<br />
<br />
 <br />
<strong class='bbc'>Introduction: The Search Area</strong><br />
 Let's assume that we have someone who wants to get from point A to point B. Let's assume that a wall separates the two points. This is illustrated below, with green being the starting point A, and red being the ending point B, and the blue filled squares being the wall in between.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/astar/image001.jpg' alt='Posted Image' class='bbc_img' /></span><br />
[Figure 1]<br />
<br />
 The first thing you should notice is that we have divided our search area into a square grid. Simplifying the search area, as we have done here, is the first step in pathfinding. This particular method reduces our search area to a simple two dimensional array. Each item in the array represents one of the squares on the grid, and its status is recorded as walkable or unwalkable. The path is found by figuring out which squares we should take to get from A to B. Once the path is found, our person moves from the center of one square to the center of the next until the target is reached.<br />
<br />
 These center points are called "nodes". When you read about pathfinding elsewhere, you will often see people discussing nodes. Why not just call them squares? Because it is possible to divide up your pathfinding area into something other than squares. They could be rectangles, hexagons, triangles, or any shape, really. And the nodes could be placed anywhere within the shapes – in the center or along the edges, or anywhere else. We are using this system, however, because it is the simplest.<br />
<br />
 <br />
<strong class='bbc'>Starting the Search</strong><br />
 Once we have simplified our search area into a manageable number of nodes, as we have done with the grid layout above, the next step is to conduct a search to find the shortest path. We do this by starting at point A, checking the adjacent squares, and generally searching outward until we find our target.<br />
<br />
 We begin the search by doing the following:<br />
<br />
 <ul class='bbcol decimal'><li>Begin at the starting point A and add it to an "open list" of squares to be considered. The open list is kind of like a shopping list. Right now there is just one item on the list, but we will have more later. It contains squares that might fall along the path you want to take, but maybe not. Basically, this is a list of squares that need to be checked out. </li><li>Look at all the reachable or walkable squares adjacent to the starting point, ignoring squares with walls, water, or other illegal terrain. Add them to the open list, too. For each of these squares, save point A as its "parent square". This parent square stuff is important when we want to trace our path. It will be explained more later. </li><li>Drop the starting square A from your open list, and add it to a "closed list" of squares that you don't need to look at again for now.</li></ul> At this point, you should have something like the following illustration. In this illustration, the dark green square in the center is your starting square. It is outlined in light blue to indicate that the square has been added to the closed list. All of the adjacent squares are now on the open list of squares to be checked, and they are outlined in light green. Each has a gray pointer that points back to its parent, which is the starting square.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/astar/image002.jpg' alt='Posted Image' class='bbc_img' /></span><br />
[Figure 2]<br />
<br />
 Next, we choose one of the adjacent squares on the open list and more or less repeat the earlier process, as described below. But which square do we choose? The one with the lowest F cost.<br />
<br />
 <br />
<strong class='bbc'>Path Scoring</strong><br />
 The key to determining which squares to use when figuring out the path is the following equation:<br />
<br />
 F = G + H<br />
<br />
 where<br />
<br />
 <ul class='bbc'><li>G = the movement cost to move from the starting point A to a given square on the grid, following the path generated to get there. </li><li>H = the estimated movement cost to move from that given square on the grid to the final destination, point B. This is often referred to as the heuristic, which can be a bit confusing. The reason why it is called that is because it is a guess. We really don't know the actual distance until we find the path, because all sorts of things can be in the way (walls, water, etc.). You are given one way to calculate H in this tutorial, but there are many others that you can find in other articles on the web.</li></ul> Our path is generated by repeatedly going through our open list and choosing the square with the lowest F score. This process will be described in more detail a bit further in the article. First let's look more closely at how we calculate the equation.<br />
<br />
 As described above, G is the movement cost to move from the starting point to the given square using the path generated to get there. In this example, we will assign a cost of 10 to each horizontal or vertical square moved, and a cost of 14 for a diagonal move. We use these numbers because the actual distance to move diagonally is the square root of 2 (don't be scared), or roughly 1.414 times the cost of moving horizontally or vertically. We use 10 and 14 for simplicity's sake. The ratio is about right, and we avoid having to calculate square roots and we avoid decimals. This isn't just because we are dumb and don't like math. Using whole numbers like these is a lot faster for the computer, too. As you will soon find out, pathfinding can be very slow if you don't use short cuts like these.<br />
<br />
 Since we are calculating the G cost along a specific path to a given square, the way to figure out the G cost of that square is to take the G cost of its parent, and then add 10 or 14 depending on whether it is diagonal or orthogonal (non-diagonal) from that parent square. The need for this method will become apparent a little further on in this example, as we get more than one square away from the starting square.<br />
<br />
 H can be estimated in a variety of ways. The method we use here is called the Manhattan method, where you calculate the total number of squares moved horizontally and vertically to reach the target square from the current square, ignoring diagonal movement, and ignoring any obstacles that may be in the way. We then multiply the total by 10, our cost for moving one square horizontally or vertically. This is (probably) called the Manhattan method because it is like calculating the number of city blocks from one place to another, where you can't cut across the block diagonally.<br />
<br />
 Reading this description, you might guess that the heuristic is merely a rough estimate of the remaining distance between the current square and the target "as the crow flies." This isn't the case. We are actually trying to estimate the remaining distance along the path (which is usually farther). The closer our estimate is to the actual remaining distance, the faster the algorithm will be. If we overestimate this distance, however, it is not guaranteed to give us the shortest path. In such cases, we have what is called an "inadmissible heuristic."<br />
<br />
 Technically, in this example, the Manhattan method is inadmissible because it slightly overestimates the remaining distance. But we will use it anyway because it is a lot easier to understand for our purposes, and because it is only a slight overestimation. On the rare occasion when the resulting path is not the shortest possible, it will be nearly as short. Want to know more? You can find equations and additional notes on heuristics <a href='http://www.policyalmanac.org/games/heuristics.htm' class='bbc_url' title='External link' rel='nofollow external'>here</a>.<br />
<br />
 F is calculated by adding G and H. The results of the first step in our search can be seen in the illustration below. The F, G, and H scores are written in each square. As is indicated in the square to the immediate right of the starting square, F is printed in the top left, G is printed in the bottom left, and H is printed in the bottom right.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/astar/image003.jpg' alt='Posted Image' class='bbc_img' /></span><br />
[Figure 3]<br />
<br />
 So let's look at some of these squares. In the square with the letters in it, G = 10. This is because it is just one square from the starting square in a horizontal direction. The squares immediately above, below, and to the left of the starting square all have the same G score of 10. The diagonal squares have G scores of 14.<br />
<br />
 The H scores are calculated by estimating the Manhattan distance to the red target square, moving only horizontally and vertically and ignoring the wall that is in the way. Using this method, the square to the immediate right of the start is 3 squares from the red square, for a H score of 30. The square just above this square is 4 squares away (remember, only move horizontally and vertically) for an H score of 40. You can probably see how the H scores are calculated for the other squares.<br />
<br />
 The F score for each square, again, is simply calculated by adding G and H together.<br />
<br />
 <br />
<strong class='bbc'>Continuing the Search</strong><br />
 To continue the search, we simply choose the lowest F score square from all those that are on the open list. We then do the following with the selected square:<br />
<br />
 <ul class='bbcol decimal'><li>Drop it from the open list and add it to the closed list. </li><li>Check all of the adjacent squares. Ignoring those that are on the closed list or unwalkable (terrain with walls, water, or other illegal terrain), add squares to the open list if they are not on the open list already. Make the selected square the "parent" of the new squares. </li><li>If an adjacent square is already on the open list, check to see if this path to that square is a better one. In other words, check to see if the G score for that square is lower if we use the current square to get there. If not, don't do anything.<br />On the other hand, if the G cost of the new path is lower, change the parent of the adjacent square to the selected square (in the diagram above, change the direction of the pointer to point at the selected square). Finally, recalculate both the F and G scores of that square. If this seems confusing, you will see it illustrated below.</li></ul> Okay, so let's see how this works. Of our initial 9 squares, we have 8 left on the open list after the starting square was switched to the closed list. Of these, the one with the lowest F cost is the one to the immediate right of the starting square, with an F score of 40. So we select this square as our next square. It is highlight in blue in the following illustration.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/astar/image004.jpg' alt='Posted Image' class='bbc_img' /></span><br />
[Figure 4]<br />
<br />
 First, we drop it from our open list and add it to our closed list (that's why it's now highlighted in blue). Then we check the adjacent squares. Well, the ones to the immediate right of this square are wall squares, so we ignore those. The one to the immediate left is the starting square. That's on the closed list, so we ignore that, too.<br />
<br />
 The other four squares are already on the open list, so we need to check if the paths to those squares are any better using this square to get there, using G scores as our point of reference. Let's look at the square right above our selected square. Its current G score is 14. If we instead went through the current square to get there, the G score would be equal to 20 (10, which is the G score to get to the current square, plus 10 more to go vertically to the one just above it). A G score of 20 is higher than 14, so this is not a better path. That should make sense if you look at the diagram. It's more direct to get to that square from the starting square by simply moving one square diagonally to get there, rather than moving horizontally one square, and then vertically one square.<br />
<br />
 When we repeat this process for all 4 of the adjacent squares already on the open list, we find that none of the paths are improved by going through the current square, so we don't change anything. So now that we looked at all of the adjacent squares, we are done with this square, and ready to move to the next square.<br />
<br />
 So we go through the list of squares on our open list, which is now down to 7 squares, and we pick the one with the lowest F cost. Interestingly, in this case, there are two squares with a score of 54. So which do we choose? It doesn't really matter. For the purposes of speed, it can be faster to choose the <span class='bbc_underline'>last</span> one you added to the open list. This biases the search in favor of squares that get found later on in the search, when you have gotten closer to the target. But it doesn't really matter. (Differing treatment of ties is why two versions of A* may find different paths of equal length.)<br />
<br />
 So let's choose the one just below, and to the right of the starting square, as is shown in the following illustration.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/astar/image005.jpg' alt='Posted Image' class='bbc_img' /></span><br />
[Figure 5]<br />
<br />
 This time, when we check the adjacent squares we find that the one to the immediate right is a wall square, so we ignore that. The same goes for the one just above that. We also ignore the square just below the wall. Why? Because you can't get to that square directly from the current square without cutting across the corner of the nearby wall. You really need to go down first and then move over to that square, moving around the corner in the process. (Note: This rule on cutting corners is optional. Its use depends on how your nodes are placed.)<br />
<br />
 That leaves five other squares.  The other two squares below the current square aren't already on the open list, so we add them and the current square becomes their parent. Of the other three squares, two are already on the closed list (the starting square, and the one just above the current square, both highlighted in blue in the diagram), so we ignore them. And the last square, to the immediate left of the current square, is checked to see if the G score is any lower if you go through the current square to get there. No dice. So we're done and ready to check the next square on our open list.<br />
<br />
 We repeat this process until we add the target square to the closed list, at which point it looks something like the illustration below.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/astar/image006.jpg' alt='Posted Image' class='bbc_img' /></span><br />
[Figure 6]<br />
<br />
 Note that the parent square for the square two squares below the starting square has changed from the previous illustration. Before it had a G score of 28 and pointed back to the square above it and to the right. Now it has a score of 20 and points to the square just above it. This happened somewhere along the way on our search, where the G score was checked and it turned out to be lower using a new path – so the parent was switched and the G and F scores were recalculated. While this change doesn't seem too important in this example, there are plenty of possible situations where this constant checking will make all the difference in determining the best path to your target.<br />
<br />
 So how do we determine the path? Simple, just start at the red target square, and work backwards moving from one square to its parent, following the arrows. This will eventually take you back to the starting square, and that's your path. It should look like the following illustration. Moving from the starting square A to the destination square B is simply a matter of moving from the center of each square (the node) to the center of the next square on the path, until you reach the target.<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/astar/image007.jpg' alt='Posted Image' class='bbc_img' /></span><br />
[Figure 7]<br />
<br />
 <br />
<strong class='bbc'>Summary of the A* Method</strong><br />
 Okay, now that you have gone through the explanation, let's lay out the step-by-step method all in one place:<br />
<br />
 <ul class='bbcol decimal'><li>Add the starting square (or node) to the open list. </li><li>Repeat the following:<br />a) Look for the lowest F cost square on the open list. We refer to this as the current square.<br />b) Switch it to the closed list.<br />c) For each of the 8 squares adjacent to this current square …<ul class='bbc'><li>If it is not walkable or if it is on the closed list, ignore it. Otherwise do the following. </li><li>If it isn't on the open list, add it to the open list. Make the current square the parent of this square. Record the F, G, and H costs of the square. </li><li>If it is on the open list already, check to see if this path to that square is better, using G cost as the measure. A lower G cost means that this is a better path. If so, change the parent of the square to the current square, and recalculate the G and F scores of the square. If you are keeping your open list sorted by F score, you may need to resort the list to account for the change.</li></ul> <br />d) Stop when you: <ul class='bbc'><li>Add the target square to the closed list, in which case the path has been found (see note below), or </li><li>Fail to find the target square, and the open list is empty. In this case, there is no path.</li></ul>  </li><li>Save the path. Working backwards from the target square, go from each square to its parent square until you reach the starting square. That is your path.</li></ul> <span class='bbc_underline'>Note</span>: In earlier versions of this article, it was suggested that you can stop when the target square (or node) has been added to the open list, rather than the closed list. Doing this will be faster and it will <span class='bbc_underline'>almost</span> always give you the shortest path, but not always. Situations where doing this could make a difference are when the movement cost to move from the second to the last node to the last (target) node can vary significantly -- as in the case of a river crossing between two nodes, for example.<br />
<br />
 <br />
<strong class='bbc'>Small Rant</strong><br />
 Forgive me for digressing, but it is worth pointing out that when you read various discussions of A* pathfinding on the web and in assorted forums, you will occasionally see someone refer to certain code as A* when it isn't. For the A* method to be used, you need to include the elements just discussed above -- specifically open and closed lists and path scoring using F, G, and H. There are lots of other pathfinding algorithms, but those other methods are not A*, which is generally considered to be the best of the lot. Bryan Stout discusses many of them in the article referenced at the end of this article, including some of their pros and cons. Sometimes alternatives are better under certain circumstances, but you should understand what you are getting into. Okay, enough ranting. Back to the article.<br />
<br />
 <br />
<strong class='bbc'>Notes on Implementation</strong><br />
 Now that you understand the basic method, here are some additional things to think about when you are writing your own program. Some of the following materials reference the program I wrote in C++ and Blitz Basic, but the points are equally valid in other languages.<br />
<br />
 <strong class='bbc'><em class='bbc'>1. Other Units (collision avoidance):</em></strong> If you happen to look closely at my example code, you will notice that it completely ignores other units on the screen. The units pass right through each other. Depending on the game, this may be acceptable or it may not. If you want to consider other units in the pathfinding algorithm and have them move around one another, I suggest that you only consider units that are either stopped or adjacent to the pathfinding unit at the time the path is calculated, treating their current locations as unwalkable. For adjacent units that are moving, you can discourage collisions by penalizing nodes that lie along their respective paths, thereby encouraging the pathfinding unit to find an alternate route (described more under #2).<br />
<br />
 If you choose to consider other units that are moving and not adjacent to the pathfinding unit, you will need to develop a method for predicting where they will be at any given point in time so that they can be dodged properly. Otherwise you will probably end up with strange paths where units zig-zag to avoid other units that aren't there anymore.<br />
<br />
 You will also, of course, need to develop some collision detection code because no matter how good the path is at the time it is calculated, things can change over time. When a collision occurs a unit must either calculate a new path or, if the other unit is moving and it is not a head-on collision, wait for the other unit to step out of the way before proceeding with the current path.<br />
<br />
 These tips are probably enough to get you started. If you want to learn more, here are some links that you might find helpful:<br />
<br />
 <ul class='bbc'><li><a href='http://www.red3d.com/cwr/steer/' class='bbc_url' title='External link' rel='nofollow external'>Steering Behavior for Autonomous Characters</a>: Craig Reynold's work on steering is a bit different from pathfinding, but it can be integrated with pathfinding to make a more complete movement and collision avoidance system. </li><li><a href='http://ducati.doc.ntu.ac.uk/uksim/uksim%2704/Papers/Simon%20Tomlinson-%2004-20/paper04-20%20CR.pdf' class='bbc_url' title='External link' rel='nofollow external'>The Long and Short of Steering in Computer Games</a>: An interesting survey of the literature on steering and pathfinding. This is a pdf file. </li><li><a href='http://www.gamasutra.com/features/game_design/19990122/movement_01.htm' class='bbc_url' title='External link' rel='nofollow external'>Coordinated Unit Movement</a>: First in a two-part series of articles on formation and group-based movement by Age of Empires designer Dave Pottinger. </li><li><a href='http://www.gamasutra.com/features/19990129/implementing_01.htm' class='bbc_url' title='External link' rel='nofollow external'>Implementing Coordinated Movement</a>: Second in Dave Pottinger's two-part series.</li></ul> <strong class='bbc'><em class='bbc'>2. Variable Terrain Cost:</em></strong> In this tutorial and my accompanying program, terrain is just one of two things – walkable or unwalkable. But what if you have terrain that is walkable, but at a higher movement cost? Swamps, hills, stairs in a dungeon, etc. – these are all examples of terrain that is walkable, but at a higher cost than flat, open ground. Similarly, a road might have a lower movement cost than the surrounding terrain.<br />
<br />
 This problem is easily handled by adding the terrain cost in when you are calculating the G cost of any given node. Simply add a bonus cost to such nodes. The A* pathfinding algorithm is already written to find the lowest cost path and should handle this easily. In the simple example I described, when terrain is only walkable or unwalkable, A* will look for the shortest, most direct path. But in a variable-cost terrain environment, the least cost path might involve traveling a longer distance – like taking a road around a swamp rather than plowing straight through it.<br />
<br />
 An interesting additional consideration is something the professionals call "influence mapping." Just as with the variable terrain costs described above, you could create an additional point system and apply it to paths for AI purposes. Imagine that you have a map with a bunch of units defending a pass through a mountain region. Every time the computer sends somebody on a path through that pass, it gets whacked. If you wanted, you could create an influence map that penalized nodes where lots of carnage is taking place. This would teach the computer to favor safer paths, and help it avoid dumb situations where it keeps sending troops through a particular path, just because it is shorter (but also more dangerous).<br />
<br />
 Yet another possible use is penalizing nodes that lie along the paths of nearby moving units. One of the downsides of A* is that when a group of units all try to find paths to a similar location, there is usually a significant amount of overlap, as one or more units try to take the same or similar routes to their destinations. Adding a penalty to nodes already 'claimed' by other units will help ensure a degree of separation, and reduce collisions. Don't treat such nodes as unwalkable, however, because you still want multiple units to be able to squeeze through tight passageways in single file, if necessary. Also, you should only penalize the paths of units that are near the pathfinding unit, not all paths, or you will get strange dodging behavior as units avoid paths of units that are nowhere near them at the time. Also, you should only penalize path nodes that lie along the current and future portion of a path, not previous path nodes that have already been visited and left behind.<br />
<br />
 <strong class='bbc'><em class='bbc'>3. Handling Unexplored Areas:</em></strong> Have you ever played a PC game where the computer always knows exactly what path to take, even though the map hasn't been explored yet? Depending upon the game, pathfinding that is too good can be unrealistic. Fortunately, this is a problem that is can be handled fairly easily.<br />
<br />
 The answer is to create a separate "knownWalkability" array for each of the various players and computer opponents (each player, not each unit -- that would require a lot more computer memory). Each array would contain information about the areas that the player has explored, with the rest of the map assumed to be walkable until proven otherwise. Using this approach, units will wander down dead ends and make similar wrong choices until they have learned their way around. Once the map is explored, however, pathfinding would work normally.<br />
<br />
 <strong class='bbc'><em class='bbc'>4. Smoother Paths:</em></strong> While A* will automatically give you the shortest, lowest cost path, it won't automatically give you the smoothest looking path. Take a look at the final path calculated in our example (in Figure 7). On that path, the very first step is below, and to the right of the starting square. Wouldn't our path be smoother if the first step was instead the square directly below the starting square?<br />
<br />
 There are several ways to address this problem. While you are calculating the path you could penalize nodes where there is a change of direction, adding a penalty to their G scores. Alternatively, you could run through your path after it is calculated, looking for places where choosing an adjacent node would give you a path that looks better. For more on the whole issue, check out <a href='http://www.gamasutra.com/features/20010314/pinter_01.htm' class='bbc_url' title='External link' rel='nofollow external'>Toward More Realistic Pathfinding</a>, a (free, but registration required) article at Gamasutra.com by Marco Pinter.<br />
<br />
 <strong class='bbc'><em class='bbc'>5. Non-square Search Areas:</em></strong> In our example, we used a simple 2D square layout. You don't need to use this approach. You could use irregularly shaped areas. Think of the board game Risk, and the countries in that game. You could devise a pathfinding scenario for a game like that. To do this, you would need to create a table for storing which countries are adjacent to which, and a G cost associated with moving from one country to the next. You would also need to come up with a method for estimating H. Everything else would be handled the same as in the above example. Instead of using adjacent squares, you would simply look up the adjacent countries in the table when adding new items to your open list.<br />
<br />
 Similarly, you could create a waypoint system for paths on a fixed terrain map. Waypoints are commonly traversed points on a path, perhaps on a road or key tunnel in a dungeon. As the game designer, you could pre-assign these waypoints. Two waypoints would be considered "adjacent" to one another if there were no obstacles on the direct line path between them. As in the Risk example, you would save this adjacency information in a lookup table of some kind and use it when generating your new open list items. You would then record the associated G costs (perhaps by using the direct line distance between the nodes) and H costs (perhaps using a direct line distance from the node to the goal). Everything else would proceed as usual.<br />
<br />
 Amit Patel has written a brief <a href='http://theory.stanford.edu/%7Eamitp/GameProgramming/MapRepresentations.html' class='bbc_url' title='External link' rel='nofollow external'>article</a> delving into some alternatives. For another example of searching on an isometric RPG map using a non-square search area, check out my article <a href='http://www.policyalmanac.org/games/twoTiered.htm' class='bbc_url' title='External link' rel='nofollow external'>Two-Tiered A* Pathfinding</a>.<br />
<br />
 <strong class='bbc'><em class='bbc'>6. Some Speed Tips:</em></strong> As you develop your own A* program, or adapt the one I wrote, you will eventually find that pathfinding is using a hefty chunk of your CPU time, particularly if you have a decent number of pathfinding units on the board and a reasonably large map. If you read the stuff on the net, you will find that this is true even for the professionals who design games like Starcraft or Age of Empires. If you see things start to slow down due to pathfinding, here are some ideas that may speed things up:<br />
<br />
 <ul class='bbc'><li>Consider a smaller map or fewer units. </li><li>Never do path finding for more than a few units at a time. Instead put them in a queue and spread them out over several game cycles. If your game is running at, say, 40 cycles per second, no one will ever notice. But they will notice if the game seems to slow down every once in a while when a bunch of units are all calculating paths at the same time. </li><li>Consider using larger squares (or whatever shape you are using) for your map. This reduces the total number of nodes searched to find the path. If you are ambitious, you can devise two or more pathfinding systems that are used in different situations, depending upon the length of the path. This is what the professionals do, using large areas for long paths, and then switching to finer searches using smaller squares/areas when you get close to the target. If you are interested in this concept, check out my article <a href='http://www.policyalmanac.org/games/twoTiered.htm' class='bbc_url' title='External link' rel='nofollow external'>Two-Tiered A* Pathfinding</a>. </li><li>For longer paths, consider devising precalculated paths that are hardwired into the game. </li><li>Consider pre-processing your map to figure out what areas are inaccessible from the rest of the map. I call these areas "islands." In reality, they can be islands or any other area that is otherwise walled off and inaccessible. One of the downsides of A* is that if you tell it to look for paths to such areas, it will search the whole map, stopping only when every accessible square/node has been processed through the open and closed lists. That can waste a lot of CPU time. It can be prevented by predetermining which areas are inaccessible (via a flood-fill or similar routine), recording that information in an array of some kind, and then checking it before beginning a path search. </li><li>In a crowded, maze-like environment, consider tagging nodes that don't lead anywhere as dead ends. Such areas can be manually pre-designated in your map editor or, if you are ambitious, you could develop an algorithm to identify such areas automatically. Any collection of nodes in a given dead end area could be given a unique identifying number. Then you could safely ignore all dead ends when pathfinding, pausing only to consider nodes in a dead end area if the starting location or destination happen to be in the particular dead end area in question.</li></ul> <strong class='bbc'><em class='bbc'>7. Maintaining the Open List:</em></strong> This is actually one of the most time consuming elements of the A* pathfinding algorithm. Every time you access the open list, you need to find the square that has the lowest F cost. There are several ways you could do this. You could save the path items as needed, and simply go through the whole list each time you need to find the lowest F cost square. This is simple, but really slow for long paths. This can be improved by maintaining a sorted list and simply grabbing the first item off the list every time you need the lowest F-cost square. When I wrote my program, this was the first method I used.<br />
<br />
 This will work reasonably well for small maps, but it isn't the fastest solution. Serious A* programmers who want real speed use something called a binary heap, and this is what I use in my code. In my experience, this approach will be at least 2-3 times as fast in most situations, and geometrically faster (10+ times as fast) on longer paths. If you are motivated to find out more about binary heaps, check out my article, <a href='http://www.policyalmanac.org/games/binaryHeaps.htm' class='bbc_url' title='External link' rel='nofollow external'>Using Binary Heaps in A* Pathfinding</a>.<br />
<br />
 Another possible bottleneck is the way you clear and maintain your data structures between pathfinding calls. I personally prefer to store everything in arrays. While nodes can be generated, recorded and maintained in a dynamic, object-oriented manner, I find that the amount of time needed to create and delete such objects adds an extra, unnecessary level of overhead that slows things down. If you use arrays, however, you will need to clean things up between calls. The last thing you will want to do in such cases is spend time zero-ing everything out after a pathfinding call, especially if you have a large map.<br />
<br />
 I avoid this overhead by creating a 2d array called whichList(x,y) that designates each node on my map as either on the open list or closed list. After pathfinding attempts, I do not zero out this array. Instead I reset the values of onClosedList and onOpenList in every pathfinding call, incrementing both by +5 or something similar on each path finding attempt. This way, the algorithm can safely ignore as garbage any data left over from previous pathfinding attempts. I also store values like F, G and H costs in arrays. In this case, I simply write over any pre-existing values and don't bother clearing the arrays when I'm done.<br />
<br />
 Storing data in multiple arrays consumes more memory, though, so there is a trade off. Ultimately, you should use whatever method you are most comfortable with.<br />
<br />
 <strong class='bbc'><em class='bbc'>8. Dijkstra's Algorithm:</em></strong> While A* is generally considered to be the best pathfinding algorithm (see rant above), there is at least one other algorithm that has its uses - Dijkstra's algorithm. Dijkstra's is essentially the same as A*, except there is no heuristic (H is always 0). Because it has no heuristic, it searches by expanding out equally in every direction. As you might imagine, because of this Dijkstra's usually ends up exploring a much larger area before the target is found. This generally makes it slower than A*.<br />
<br />
 So why use it? Sometimes we don't know where our target destination is. Say you have a resource-gathering unit that needs to go get some resources of some kind. It may know where several resource areas are, but it wants to go to the closest one. Here, Dijkstra's is better than A* because we don't know which one is closest. Our only alternative is to repeatedly use A* to find the distance to each one, and then choose that path. There are probably countless similar situations where we know the kind of location we might be searching for, want to find the closest one, but not know where it is or which one might be closest.<br />
<br />
 <br />
<strong class='bbc'>Further Reading</strong><br />
 Okay, now you have the basics and a sense of some of the advanced concepts. At this point, I'd suggest wading into my source code. The package contains two versions, one in C++ and one in Blitz Basic. Both versions are heavily commented and should be fairly easy to follow, relatively speaking. Here is the link.<br />
<br />
 <ul class='bbc'><li><a href="http://www.blitzcoder.com/cgi-bin/showcase/showcase_showentry.pl?id=turtle177604062002002208&comments=no">Sample Code: A* Pathfinder (2D) Version 1.9</li></ul> If you do not have access to C++ or Blitz Basic, two small exe files can be found in the C++ version. The Blitz Basic version can be run by downloading the free demo version of Blitz Basic 3D (not Blitz Plus) at the <a href='http://www.blitzbasic.com/' class='bbc_url' title='External link' rel='nofollow external'>Blitz Basic</a> web site.<br />
<br />
 You should also consider reading through the following web pages. They should be much easier to understand now that you have read this tutorial.<br />
<br />
 <ul class='bbc'><li><a href='http://www-cs-students.stanford.edu/%7Eamitp/gameprog.html#Paths' class='bbc_url' title='External link' rel='nofollow external'>Amit's A* Pages</a>: This is a very widely referenced page by Amit Patel, but it can be a bit confusing if you haven't read this article first. Well worth checking out. See especially Amit's own <a href='http://theory.stanford.edu/%7Eamitp/GameProgramming/' class='bbc_url' title='External link' rel='nofollow external'>thoughts</a> on the topic. </li><li><a href='http://www.gamasutra.com/features/19970801/pathfinding.htm' class='bbc_url' title='External link' rel='nofollow external'>Smart Moves: Intelligent Path Finding</a>: This article by Bryan Stout at Gamasutra.com requires registration to read. The registration is free and well worth it just to reach this article, much less the other resources that are available there. The program written in Delphi by Bryan helped me learn A*, and it is the inspiration behind my A* program. It also describes some alternatives to A*. </li><li><a href='http://www.gamasutra.com/features/gdcarchive/2000/pottinger.doc' class='bbc_url' title='External link' rel='nofollow external'>Terrain Analysis</a>: This is an advanced, but interesting, article by Dave Pottinger, a professional at Ensemble Studios. This guy coordinated the development of Age of Empires and Age of Kings. Don't expect to understand everything here, but it is an interesting article that might give you some ideas of your own. It includes some discussion of mip-mapping, influence mapping, and some other advanced AI/pathfinding concepts.</li></ul> Some other sites worth checking out:<br />
<br />
 <ul class='bbc'><li><a href='http://www.aiguru.com/pathfinding.htm' class='bbc_url' title='External link' rel='nofollow external'>aiGuru: Pathfinding</a> </li><li><a href='http://www.gameai.com/pathfinding.html' class='bbc_url' title='External link' rel='nofollow external'>Game AI Resource: Pathfinding</a> </li><li><a href='http://www.gamedev.net/reference/list.asp?categoryid=18#94' class='bbc_url' title=''>GameDev.net: Pathfinding</a></li></ul> Well, that's it. If you happen to write a program that uses any of these concepts, I'd love to see it. I can be reached at<br />
<br />
 <span rel='lightbox'><img src='http://images.gamedev.net/features/programming/astar/mail2.jpg' alt='Posted Image' class='bbc_img' /></span><br />
<br />
 Until then, good luck!<br />
<br />
]]></description>
		<pubDate>Thu, 09 Oct 2003 02:33:36 +0000</pubDate>
		<guid isPermaLink="false">d2a9aaedbe3616c7be11e07856c29e2a</guid>
	</item>
	<item>
		<title>Vehicle Control with Neural Networks</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/vehicle-control-with-neural-networks-r1988</link>
		<description><![CDATA[<br />
<strong class='bbc'>Abstract</strong><br />
 Using a neural network for the brain, we want a vehicle to drive by itself avoiding obstacles. We accomplish this by choosing the appropriate inputs/outputs and by carefully training the neural net. We feed the network with distances of the closest obstacles around the vehicle to imitate what a human driver would see. The output is the acceleration and steering of the vehicle. We also need to train the network with a set of strategic input-output. The result is impressive, for a couple of neurons! The vehicle drives around avoiding obstacles, but some improvement or modification can be done to make this software work for a specific purpose.<br />
<br />
 <br />
<strong class='bbc'>Introduction</strong><br />
 The idea is to have a vehicle that drives by itself and avoids obstacles in a virtual world. Every instant, the vehicle decides by itself how to modify its speed and direction according to its environment. In order to make it more real, the AI should only see what a person would see if it was driving, so the AI's decision is only based on obstacles that are in front of the vehicle. By having a realistic input, the AI could possibly be used in a real vehicle and work just as well.<br />
<br />
 Gaming is the first use I think of when I hear "AI controlling a vehicle". Many driving games could use this technique to control vehicles, but there are a number of other applications that could be found for software that controls a vehicle in a virtual world, or in the real world.<br />
<br />
 So how do we do this? There are many AI techniques out there, but since we need a "brain" to control the vehicle, neural networks would do the job. Neural networks are based on how our brain works; they seems to be the right choice. We will need to define what the input and output should be for this neural network.<br />
<br />
 <br />
<strong class='bbc'>Neural Networks</strong><br />
 The Neural Network Artificial Intelligence comes from how brains work. Our brain is composed of 10<sup class='bbc'>11</sup> neuron cells that send electrical signal to each other. Each neuron is composed of one or two axon which work as output and many dendrites which work as input of electrical signals. Neurons need a certain strength of signal input that adds up from all the dendrites to be triggered. Once triggered, the neuron will fire and send an electrical signal down its axon to other neurons. Connections (axon and dendrites) will strengthen if they are often used.<br />
<br />
 This principle is applied to neural networks on a smaller scale. Today's computers don't have the power of computing that 20 billion neurons do, but even with a few neurons, we are able to have intelligent response from a neural network.<br />
<br />
 Neurons are organized in layers as figure 1 shows. The input layer will have entries, and depending on the strength of connection to each neuron in the next layer, the input signal is sent to the next layer. The strength of the connection is called a weight. The value of each neuron in each layer will depend on the weight of the connection and the values of the neurons of the previous layer.<br />
<br />
 1988/figure1.png<br />
Figure 1: Basic Neural Network<br />
<br />
 A driver could be compared to a "function". There are different inputs: what the driver sees. This data is processed by the brain as a function and the response of the driver is the output of the function.<br />
<br />
 A function f(x) = y transforms a value x (one dimension) into y (one dimension).<br />
<br />
 We use a back propagation neural network for the "brain" of the driver because such a neural network is capable of approximating any function with a domain and a range that each have multiple dimensions: f(x1,x2,…,xn) = y1,y2,…,ym<br />
<br />
 That is exactly what we need here since we need multiple inputs and multiple outputs.<br />
<br />
 When a neural network has just a couple of neurons, we can compute what the weight should be to get the desired response. But as we increase the number of neurons we use, we also increase the complexity of computing what the weight should be. A back propagation network lets us train the neural network which sets the weights for us. We just need to provide the desired outputs with the corresponding inputs.<br />
<br />
 After being trained, the neural network will respond close to the desired output when a known input is given and will "guess" a response for any input that doesn't exactly match the trained input-output.<br />
<br />
 The actual equations are out of the scope of this article. There are plenty of good books that explain how neural networks with back propagation works.<br />
<br />
 The neural network used in this case has 4 layers (Figure 2). I tried many different combinations, from 3 layers to 6 layers. It worked OK with 3 layers but when I trained it with at set of 22 inputs-outputs, the approximation of the function wasn't accurate enough. 5 and 6 layers work fine, but training it took a while (up to 20 or 30 minutes on a PII) and when I ran the program it took a lot of computation time from the CPU.<br />
<br />
 My input layer has 3 neurons, and the output layer has 2. I'll explain why later. The 2 layers in between have 8 neurons each. Again, I tried layers with more neurons and less neurons and settled for 8 since it was doing an appropriate job.<br />
<br />
 When choosing the number of neurons, keep in mind that each layer and each neuron you add to the system will add computation time to calculate the weights.<br />
<br />
 1988/figure2.png<br />
Figure 2: 3-8-8-2 Neural Network<br />
<br />
 <strong class='bbc'>Adding Neurons:</strong><br />
We have the input layer I with i neurons, and output layer O with o neurons. We want to add one neuron to the middle layer M. The number of connections between neurons that we add is (i+o).<br />
<br />
 <strong class='bbc'>Adding Layers:</strong><br />
We have the input layer I with i neurons, and output layer O with o neurons. We want to a layer M with m neurons. The number of connections between neurons that we add is (m x (i+o)).<br />
<br />
 Now that we have covered how the "brain" works, we need to understand how to define the inputs and outputs of the neural network. The neural network by itself doesn't do anything if we don't give it the information from the virtual world and plug the neural network's response back in to control the vehicle.<br />
<br />
 <br />
<strong class='bbc'>The Input</strong><br />
 What information is important in controlling a vehicle when we are driving? Firstly, we need the position of obstacles relative to us. Is it to our right, to our left or straight ahead? If there are buildings on both side of the road, but none if front, we will accelerate. But if a car is stopped in front of us, we will brake. Secondly, we need the distance from our position to the object. If an object is far away we will continue driving until it is close, in which case, we will slowdown or stop.<br />
<br />
 That is exactly the information that we use for our neural network. To keep it simple we have three relative directions: left, front and right. And we need the distance from the obstacle to the vehicle.<br />
<br />
 1988/figure3.png<br />
Figure 3<br />
<br />
 We will define what kind of field of vision our AI driver should see and make a list of all the objects it can see. For simplicity we are using a circle in our example but we could use a real frustum with 6 intersecting planes. Now for each object in this circle, we check to see if it is in the left field of view, right field of view or center.<br />
<br />
 The input to the neural network will be an array: float Vision [3]. The distance to the closest obstacle to the left, center, and right of the vehicle will be stored in Vision [0], Vision [1] and Vision [2] respectively. In Figure 3, we show how the array works. The obstacle on the left is at 80% of the maximum distance, the obstacle on the right is at 40% of the maximum distance and there is no obstacle in the center.<br />
<br />
 To be able to do this, we need the position (x,y) of every object, the position (x,y) of the vehicle and the angle of the vehicle. We also need 'r' (the radius of the circle) and d<sub class='bbc'>right</sub>, d<sub class='bbc'>left</sub>, the vectors from the craft to the lines L<sub class='bbc'>right</sub>, L<sub class='bbc'>left</sub>. Those lines are parallel to the direction of the craft. Both vectors are perpendicular to the lines.<br />
<br />
 Even though it is a 3D world, all the mathematics is 2D because the vehicle doesn't go into the 3<sup class='bbc'>rd</sup> dimension since it is not flying. All the equations will only consider x and y and not z.<br />
<br />
 First, we compute the equations of the lines L<sub class='bbc'>right</sub> and L<sub class='bbc'>left</sub> which will help us determine whether an obstacle is to the left, right or center of the vehicle.<br />
<br />
 Check figure 4 for an illustration of all the variables.<br />
<br />
 1988/formula1.png<br />
<br />
 with<br />
<br />
 1988/formula2.png<br />
<br />
 Then we compute a point on the line<br />
<br />
 1988/formula3.png<br />
<br />
 with V<sub class='bbc'>x</sub>, V<sub class='bbc'>y</sub> the position of the vehicle.<br />
<br />
 Then we can finally compute c<sub class='bbc'>R</sub><br />
<br />
 1988/formula4.png<br />
<br />
 We proceed the same way to compute the equation of the line L<sub class='bbc'>left</sub> using the vector d<sub class='bbc'>left</sub>.<br />
<br />
 Second, we need to compute the center of the circle. Anything within the circle will be seen by the AI. The center of the circle C(x,y) is at the distance r from the vehicle's position V(x,y).<br />
<br />
 1988/formula5.png<br />
<br />
 1988/formula6.png<br />
<br />
 with V<sub class='bbc'>x</sub>, V<sub class='bbc'>y</sub> the position of the vehicle and C<sub class='bbc'>x</sub>, C<sub class='bbc'>y</sub> the center of the circle.<br />
<br />
 1988/figure4.png<br />
Figure 4<br />
<br />
 Then we check every object in the world to find out if they are within the circle (if the objects are organized in quadtree or octtree, the process is much faster than with a linked list).<br />
<br />
 If 1988/formula7.png then the object is within the circle, with O<sub class='bbc'>x</sub>, O<sub class='bbc'>y</sub> the position of the obstacle.<br />
<br />
 For every object within the circle, we then must check if they are to the right, left or center of the vehicle.<br />
<br />
 If 1988/formula8.png then the object is in the right part of the circle<br />
<br />
 else if 1988/formula9.png then the object is in the left part of the circle<br />
<br />
 else it is in the center.<br />
<br />
 We compute the distance from the object to the vehicle<br />
<br />
 1988/formula10.png<br />
<br />
 Now we store the distance in the appropriate part of the array (Vision[0], Vision[1] or Vision[2]) only if the distance already stored is larger than the distance we just computed. The Vision must have been initialized to 2r prior to that.<br />
<br />
 After checking every object, we have the Vision array with the distance to the closest object to the right, center and left of the vehicle. If no object were found for one of those sections, we will have the default value <sub class='bbc'>1988/formula11.png</sub> which means: "no object in view".<br />
<br />
 Because the neural network is a using a sigmoid function, the input needs to be between 0.0 and 1.0. 0.0 should mean that an object is touching the vehicle and 1.0 means that there is no object as far at it can see. Since we set a number for the maximum distance the AI driver should see, we can easily modify all the distances to a floating point between 0.0 and 1.0.<br />
<br />
 1988/formula12.png<br />
<br />
 <br />
<strong class='bbc'>The output</strong><br />
 The output needs to control the vehicle's speed and direction. That would be the acceleration, the brake and the steering wheel. So we need 2 outputs; one will be the acceleration/brake since the brake is just a negative acceleration, and the other will be the change in direction.<br />
<br />
 The output from the neural network is also between 0.0 and 1.0 for the same reason as the input. For the acceleration, 0.0 means "full brakes on"; 1.0 means "full gas" and 0.5 means no gas or acceleration. For the steering, 0.0 means full left, 1.0 means full right and 0.5 means strait ahead. So we need to translate the output into values that can be used.<br />
<br />
 1988/formula13.png<br />
<br />
 1988/formula14.png<br />
<br />
 We should note that a "negative acceleration" means braking if the vehicles is moving forward, but it also means going into reverse if the vehicle is at rest. Similarly, a "positive acceleration" means braking if the vehicle is moving in reverse.<br />
<br />
 <br />
<strong class='bbc'>Training</strong><br />
 As I mentioned earlier, we need to train the neural network to approximate the function we need it to accomplish. We need to create a set of input-output that would be the main reaction we want the neural network to have.<br />
<br />
 Choosing the right input-output to train a neural network is probably the trickiest part of all. I had to train the network with a set of input-output, see how it reacted in an environment, and modify the entries as needed. Depending on how we train the network, the vehicle can hesitate in some situations and get immobilized.<br />
<br />
 We make a table (Table 1) with different arrangements of obstacle positions relative to the vehicle and the desired reaction from the AI.<br />
<br />
 Table 1<br />
<br />
   Input Neurons<br />
Relative distance to obstacle Output Neurons   <strong class='bbc'>Left</strong> <strong class='bbc'>Center</strong> <strong class='bbc'>Right</strong> <strong class='bbc'>Acceleration</strong> <strong class='bbc'>Turn</strong>   No obstacle No obstacle No obstacle Full Acceleration straight   Half way No obstacle No obstacle Accelerate a bit Little bit to the right   No obstacle No obstacle Half way Accelerate a bit Little bit to the left   No obstacle Half way No obstacle Slow down Little bit to the left   Half way No obstacle Half way Accelerate straight   Touching Object Touching Object Touching Object Reverse Left   Half way Half way Half way No Action Little bit to the left   Touching Object No obstacle No obstacle Slow down Full Right   No obstacle No obstacle Touching Object Slow down Full Left   No obstacle Touching Object No obstacle Reverse Left   Touching Object No obstacle Touching Object Full Acceleration straight   Touching Object Touching Object No obstacle Reverse Full Right   No obstacle Touching Object Touching Object Reverse Full Left   Object Close Object Close Object Very Close No Action Left   Object Very Close Object Close Object Close No Action Right   Touching Object Object Very Close Object Very Close Slow down Full Right   Object Very Close Object Very Close Touching Object Slow down Full Left   Touching Object Object Close Object Far No Action Right   Object Far Object Close Touching Object No Action Left   Object Very Close Object Close Object Closer than halfway No Action Full Right   Object Closer than halfway Object Close Object Very Close Slow down Full Left   And now, we translate this into numbers in Table 2.<br />
<br />
 Table 2<br />
<br />
   Input Neurons Output Neurons   <strong class='bbc'>Left</strong> <strong class='bbc'>Center</strong> <strong class='bbc'>Right</strong> <strong class='bbc'>Acceleration</strong> <strong class='bbc'>Turn</strong>   1.0 1.0 1.0 1.0 0.5   0.5 1.0 1.0 0.6 0.7   1.0 1.0 0.5 0.6 0.3   1.0 0.5 1.0 0.3 0.4   0.5 1.0 0.5 0.7 0.5   0.0 0.0 0.0 0.2 0.2   0.5 0.5 0.5 0.5 0.4   0.0 1.0 1.0 0.4 0.9   1.0 1.0 0.0 0.4 0.1   1.0 0.0 1.0 0.2 0.2   0.0 1.0 0.0 1.0 0.5   0.0 0.0 1.0 0.3 0.8   1.0 0.0 0.0 0.3 0.2   0.3 0.4 0.1 0.5 0.3   0.1 0.4 0.3 0.5 0.7   0.0 0.1 0.2 0.3 0.9   0.2 0.1 0.0 0.3 0.1   0.0 0.3 0.6 0.5 0.8   0.6 0.3 0.0 0.5 0.2   0.2 0.3 0.4 0.5 0.9   0.4 0.3 0.2 0.4 0.1   <strong class='bbc'>Input:</strong><br />
0.0 : Object almost touching vehicle.<br />
1.0 : Object at maximum view distance or no object in view<br />
<br />
 <strong class='bbc'>Output:</strong><br />
<em class='bbc'>Acceleration</em><br />
0.0 : Maximum negative acceleration (brake or reverse)<br />
1.0 : Maximum positive acceleration<br />
<em class='bbc'>Turn</em><br />
0.0 : Full left turn<br />
0.5 : Straight<br />
1.0 : Full Right turn<br />
<br />
 <br />
<strong class='bbc'>Conclusion / Improvement</strong><br />
 Using a neural network with back propagation works well for our purposes, but there are some problems once implemented and tested. Some improvement or modification can be done to either make the program more reliable or to adapt it to other situations. I will now address some of the problems you might be thinking about right now.<br />
<br />
 1988/figure5.png<br />
Figure 5<br />
<br />
 The vehicle does get "stuck" once in a while because it hesitates deciding whether it should go right or left. That should be expected: humans have the same problem sometimes. Fixing this problem is not so easy if we try to tweak the weights of the neural network. But we can easily add a line of code that says:<br />
<br />
 "If (vehicle doesn't move for 5 seconds) then (take over the controls and make it turn 90 degrees right)".<br />
<br />
 With this simple check, we ensure that the vehicle will never get in a place not knowing what to do.<br />
<br />
 The vehicle will not see a small gap between two buildings as shown in figure 5. Since we don't have a high level of precision in the vision (left, center, right), two buildings close together will seems like a wall for the AI. To have better vision of our AI, we need to have 5 or 7 levels of precision in the input for the neural network. Instead of having "right, center, left" we could have "far right, close right, center, close left, far left". With a careful training of the neural network, the AI will see the gap and realize that it can go through it.<br />
<br />
 This works in a "2D" world, but what if we have a vehicle capable of flying through a cave? With some modification of this technique, we can have the AI fly rather than drive. Similar to the last problem, we add precision to the vision. But instead of adding a "far right" and a "far left", we can do as shown in Table 3.<br />
<br />
 Table 3<br />
<br />
   Upper left Up Upper right   Left Center Right   Lower left Down Lower right   Now that our neural network can see in 3D we just need to modify our controls and the physics on how the vehicle reacts to the world.<br />
<br />
 All the vehicle does is "wander around" without purpose. It doesn't do anything other than avoiding obstacle. Depending on why we need an AI driven vehicle, we can "swap" brains as needed. We can have a set of different neural networks and use the right one according to the situation. For example, we might want the vehicle to follow a second vehicle if it is in its field of view. We just need to plug another neural network trained to follow another vehicle with the position of the second vehicle as input.<br />
<br />
 As we have just seen, this technique can be improved and used in many different areas. Even if it is not applied to any useful purpose, it is still interesting to see how an artificial intelligent system reacts. If we watch it long enough, we realize that in a complex environment, the vehicle will not always take the same path and because of the small difference in decision due to the nature of neural network, the vehicle will sometimes drive to the left of a building, and sometimes to the right of the same building.<br />
<br />
 <br />
<strong class='bbc'>References</strong><br />
 Joey Rogers, <a href='http://www.amazon.com/exec/obidos/ASIN/0125931158/ref=nosim/gamedev' class='bbc_url' title='External link' rel='nofollow external'>Object-Oriented Neural Network in C++</a>, Academic Press, San Diego, CA, 1997<br />
<br />
 M.T. Hagan, H.B. Demuth and M.H. Beale, <a href='http://www.amazon.com/exec/obidos/ASIN/0534943322/ref=nosim/gamedev' class='bbc_url' title='External link' rel='nofollow external'>Neural Network Design</a>, PWS Publishing, Boston, MA, 1995<br />
<br />
]]></description>
		<pubDate>Mon, 01 Sep 2003 11:34:16 +0000</pubDate>
		<guid isPermaLink="false">05751401fb782aa43ddf0bc31c121b7b</guid>
	</item>
	<item>
		<title>Precalculated Pathfinding Revisited</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/precalculated-pathfinding-revisited-r1939</link>
		<description><![CDATA[Precalculated Pathfinding Revisited<br />
by <a href='mailto:rfine@tbrf.net' title='E-mail Link' class='bbc_email'>Richard "superpig" Fine</a><br />
<br />
 This is a follow-up-slash-rewrite of an article I wrote a while back on a technique I called 'Precalculated Pathfinding.' There were a few problems I didn't address, partly because I didn't have answers to them and partly because they hadn't occurred to me. Well, after recently solving the problem which bugged me the most (the problem of dynamic networks), I've decided to attack this thing again. I'll give a complete description of the initial technique again too, so you don't have to go and find the other article.<br />
<br />
 Precalculated Pathfinding (or "Fine's algorithms" as I hope they will come to be known ;-) ) is a way of storing all possible paths through a network, eliminating most real-time pathfinding operations. It's also a very useful way of having an AI 'learn' the paths through a network. However, it's a trade - memory for speed. Also, the fact that the routes are 'precalculated' - calculated once, before the game begins - means that you have to respond to changes in the world (which may create or block routes through the network). I'll be addressing both these problems.<br />
<br />
 <br />
<strong class='bbc'>Initial Concept</strong><br />
 Given that the route ABCD is the shortest route from A to D, it can be proven that BCD is the shortest route from B to D. It's as if any given 'shortest route' is made up of smaller 'shortest routes.' If there were a shorter route from B to D, for example BED, then the shortest route from A to D would have to be ABED. And so on.<br />
<br />
 So, we can say something like this:<br />
<br />
 [indent]  route(A->D) = AB + route(B->D) [/indent] and we know for a fact that's the shortest route. While we're at A, it doesn't actually matter to us what the shortest route from B to D is; we just know that the we're going to use it. We can find out what it actually is once we get to B. All we're interested in right now is 'where to go next.'<br />
<br />
 <br />
<strong class='bbc'>The Foundation</strong><br />
 That 'where to go next' is a pretty powerful concept. Imagine that once we're at B, our target changes and we want to get to E? We won't have wasted any time calculating the rest of the route to D; we can instantly change our target and say 'ok, so where do we go next to get to E?'<br />
<br />
 These 'where to go next' values can be stored neatly in a table. And we love tables, don't we? Let's take the sample network:<br />
<br />
 /reference/programming/features/precalcpath/image001.gif<br />
<br />
 From this network, using any pathfinding algorithm you feel like (I just used visual inspection, so I might not always get the shortest path - but you'll get the idea), you can build the following table:<br />
<br />
 <br />
<br />
     To   <strong class='bbc'>A</strong> <strong class='bbc'>B</strong> <strong class='bbc'>C</strong> <strong class='bbc'>D</strong> <strong class='bbc'>E</strong>   From <strong class='bbc'>A</strong> - B C C E   <strong class='bbc'>B</strong> A - C C A   <strong class='bbc'>C</strong> A B - D A   <strong class='bbc'>D</strong> C C C - E   <strong class='bbc'>E</strong> A A A D -   To recap: I built this table by finding the route <strong class='bbc'>From</strong> each given node <strong class='bbc'>to</strong> each given node, and storing the first node in the route (excluding the start node).<br />
<br />
 To use the table, all you need to know is your current location, and your destination. Feeding the current location in as your 'from' value, and the destination in as your 'to' value, you get the next node you should move to. In any sensible implementation, connections between nodes are simple straight lines where no obstacles are present, so actually moving to the next node should be a cinch.<br />
<br />
 This technique also has the advantage that it can cope instantly with changes both in position and destination, without having wasted any processing time (at a time when processor real-estate is at a premium). Using conventional pathfinding techniques, you have to calculate the entire route to the target - sometimes you'll do that each time the bot reaches a new node, but you may have optimised by storing the path in the bot's "memory."<br />
<br />
 Let's say that you've calculated a path that is 10 nodes long. Your bot begins to move, but after traversing 2 nodes, the target changes (the enemy has moved, or the bot has been given new orders, or something). So, a new path is calculated, and the old one discarded. That means you processed 8 nodes which never got used - and yes, there's no way you could have predicted the path would have been discarded or when, but it's an obvious waste of processor time.<br />
<br />
 With this technique however, you process all the nodes before the game starts - perhaps even at development time, where the table can be stored in a file - and once you're in-game, you never have to waste time looking at nodes which don't get used.<br />
<br />
 Let's play a little game with our network. We'll place a 'hare' at A, set to follow the path AEDCA repeatedly. We then place our 'dog' at D, and watch it track (and, finally, catch) the hare.<br />
<br />
 <br />
<br />
   Hare Position Dog Position Dog moves to…   A D C   E C A   D A C   C C …eat the hare!   Notice how, in the third row, the dog actually doubles back on itself - if it didn't, our racetrack critters would be stuck in an endless loop (symbolic maybe, but that's far too philosophical for this article).<br />
<br />
 In a more usual game situation - because our dog-race example is based around the same simple 'terminator' AI that people realised wasn't terribly interesting several years ago - there'd be other information influencing the path. For example, each node could also contain the distance to and location of the nearest health-pack, so that the AI could choose to take a little detour to pick up a medikit, if not too far away.<br />
<br />
 The same sort of idea can be applied to all number of in-game objects the AI might find significant - ammunition, etc - things which don't move around. Of course, each time you store something else in the table, you're using up more memory, so you need to make sure you stay efficient. If you want to be aware of nearby objects which could be <strong class='bbc'>moving</strong>, then it gets a little more difficult. I'll look at such a situation later on in the article.<br />
<br />
 <br />
<strong class='bbc'>Dynamic Worlds</strong><br />
 One of the biggest problems people emailed me about after the last article was 'how do I deal with a network which changes?' For example, say a ceiling collapses somewhere, removing one of the paths between two nodes. How do we deal with that, without recalculating the entire network? I think I have a solution now (oddly enough, penned while sitting around at a game development studio, waiting for an interview), so here you go, boys and girls.<br />
<br />
 We're only going to deal with a situation where one path has been removed. We can't escape recalculation altogether in a properly dynamic network - there's no way of knowing which paths would disappear/reappear and when - so we want to minimise the number of nodes we process.<br />
<br />
 The technique uses a sort of 'ripple propagation.' As we move further away from the affected path within the network, the number of nodes needing to be processed get fewer and fewer, until eventually the network doesn't change - like how a ripple dissipates as you get further from the point of impact.<br />
<br />
 The algorithm is recursive/repetitive. For each node you feed in, you recalculate it, and compare the recalculated version to the original version. If there have been no changes, then obviously the node is not affected by the change in the network, so processing of this node stops. However, if there have been changes, then you process all nodes connected to the current node (that have not already been recalculated).<br />
<br />
 /reference/programming/features/precalcpath/image002.gif<br />
<br />
 Let's take our network from earlier, and remove the path BC:<br />
<br />
 The original path table looked like this:<br />
<br />
 <br />
<br />
     To   <strong class='bbc'>A</strong> <strong class='bbc'>B</strong> <strong class='bbc'>C</strong> <strong class='bbc'>D</strong> <strong class='bbc'>E</strong>   From <strong class='bbc'>A</strong> - B C C E   <strong class='bbc'>B</strong> A - C C A   <strong class='bbc'>C</strong> A B - D A   <strong class='bbc'>D</strong> C C C - E   <strong class='bbc'>E</strong> A A A D -   We'll keep two lists - a 'nodes to be processed' (tbP) list and a 'nodes already processed' (aP) list. To begin with, the tbP list is 'BC' and the aP list is empty.<br />
<br />
 We process the first node on the tbP list - B. Using visual inspection again, we rebuild the row in the table. In fact, in this case, we can see that B only has one path left, so all its values will have to use that path. So, the original row was:<br />
<br />
 <br />
<br />
   From <strong class='bbc'>B</strong> A - C C A   And the newly calculated row is:<br />
<br />
 <br />
<br />
   From <strong class='bbc'>B</strong> A - A A A   We can see that the row has changed. So, we get all the nodes which <strong class='bbc'>were</strong> connected to B - that is, assuming the connection BC still exists - and see if we need to process them.<br />
<br />
 The list of nodes connected to B is AC. Node A does not appear in either the tbP or aP lists so we add it to the tbP list. Node C is in the tbP list already, so we leave it alone.<br />
<br />
 That's node B done, so we move it from the tbP list to the aP list, and move to the next node in the tbP list.<br />
<br />
 The tbP list is now 'CA' and the aP list is now 'B.' The current node is now C.<br />
<br />
 The original row for C was:<br />
<br />
 <br />
<br />
   From <strong class='bbc'>C</strong> A B - D A   The newly calculated row is:<br />
<br />
 <br />
<br />
   From <strong class='bbc'>C</strong> A A - D A   It's only a small change, but it's a change. So, we get our list of nodes that used to be connected to C - 'ABD' - and work out which ones need adding to lists. A is already in the tbP list; B is in the aP list; but D is in neither, so we add it to the tbP list. Finally, we move C to the aP list.<br />
<br />
 The tbP list is now 'AD' and the aP list is now 'BC.' The current node is now A.<br />
<br />
 The original row for A was:<br />
<br />
 <br />
<br />
   From <strong class='bbc'>A</strong> - B C C E   The new row for A is:<br />
<br />
 <br />
<br />
   From <strong class='bbc'>A</strong> - B C C E   No change this time. So, we can move A to the aP list and continue processing the tbP list, without adding any more nodes.<br />
<br />
 The tbP list is now 'D' and the aP list is now 'BCA.' The current node is now D.<br />
<br />
 Original row for D:<br />
<br />
 <br />
<br />
   From <strong class='bbc'>D</strong> C C C - E   New row for D:<br />
<br />
 <br />
<br />
   From <strong class='bbc'>D</strong> C C C - E   Again, no change, so we move D across to the aP list.<br />
<br />
 Now, the aP list is 'BCAD,' but the tbP list is empty - which means we've finished. The new path table is:<br />
<br />
 <br />
<br />
     To   <strong class='bbc'>A</strong> <strong class='bbc'>B</strong> <strong class='bbc'>C</strong> <strong class='bbc'>D</strong> <strong class='bbc'>E</strong>   From <strong class='bbc'>A</strong> - B C C E   <strong class='bbc'>B</strong> A - A A A   <strong class='bbc'>C</strong> A A - D A   <strong class='bbc'>D</strong> C C C - E   <strong class='bbc'>E</strong> A A A D -   Notice that we didn't even need to process node E with this method. The path from node E to node B hasn't changed (EAB), but it could quite easily have done.<br />
<br />
 The two lists can, in fact, be combined - you could just use one list and keep a 'cursor' in it, rather than using the top node of the tbP list each time.<br />
<br />
 The method can be used for both adding paths and removing paths - you just ensure you start with the correct nodes in the tbP list.<br />
<br />
 As for adding/removing nodes, nodes are only significant in the network when they have connections. A node with no connections might just as well not exist. So, when removing a node, simply remove all of its connections (using the method described here), and when adding a node, simply change the network and propagate the change (again, using this method). The only thing you need to watch out for when adding a node is that the path table will have to be expanded to have room for the new node's routes.<br />
<br />
 Often, you'll have a situation where more than one path has to be added/removed. You could simply add/remove each path in turn; however, that would result in having to recalculate some nodes several times, rather than just the once that a single path would require. So, you can actually do as many paths as you want at once; you just make sure that all changes have been made before propagation begins, and that the tbP list contains <strong class='bbc'>all</strong> the endpoints of the affected routes. When adding routes AB and CD, you start with a tbP list of 'ABCD,' and so on. It's more efficient than propagating each path separately.<br />
<br />
 <br />
<strong class='bbc'>Education</strong><br />
 There's another interesting thing about this technique.<br />
<br />
 Let's say that rather than having one globally shared table, we give each bot in the world it's own table - and this table starts with one row/column, for the node the bot is currently at.<br />
<br />
 Now, we add all the nodes that the bot can 'see,' using the propagation method described earlier. So our bot has a limited knowledge of the world; it can traverse the part of the graph that it 'knows' about.<br />
<br />
 /reference/programming/features/precalcpath/image003.gif<br />
<br />
 We're about to need another table. I'll call this a 'magnitude' table - it's a table of the number of connections each node in the network has. For the network we've been using throughout this article:<br />
<br />
 It looks like this:<br />
<br />
 <br />
<br />
   Node Magnitude   A 3   B 2   C 3   D 2   E 2   So, how does this help us? Well, our bot can take any given node in his 'view' of the network, and compare its magnitude to the value in the table. If his value is smaller than the 'global' value, (we'll call it the 'optimum magnitude'), then it means he hasn't fully 'explored' that node yet - there are routes beyond that node that he doesn't know about yet.<br />
<br />
 So, let's give our bot a new type of idle behaviour - 'explore.' He can do it when he has no achievable goal. When exploring, what he does is to pick a nearby node with a less-than-optimum magnitude, and go to it. When he reaches it, he should be able to see other routes, thus increasing his magnitude for that node until it becomes optimum.<br />
<br />
 This behaviour could be linked to other ideas - for example, he could be instructed to stay within a certain radius of a point, or within the line of sight of a given node. It could be linked to a more complex idea: for example - the bot finds a trail of blood on the floor, increasing the probability of nearby nodes being explored relative to other nodes ('investigation'). Maybe he sees a sign saying 'danger,' which decreases the probability of nearby nodes being explored ('caution'). Simply adding a probability system to the node-picking code can be immensely powerful.<br />
<br />
 It would also not be too difficult to implement 'forgetfulness.' Simply: every now and then, pick a route in the bot's view of the network (preferably one far away), and remove it. If you'd prefer, maybe add a non-existent route (although that would mean you'd have to take care of situations where the node's magnitude is actually <strong class='bbc'>greater</strong> than the optimum).<br />
<br />
 It can be a pretty powerful behaviour. Linking it into other parts of the AI - for example, scripted sequences - could produce some impressive effects. Right now, I'm getting the image of watching a group of soldiers in explore mode, finding and opening the door to a room with an extremely large monster in, screaming, and running away. Woo!<br />
<br />
 What are the problems with this technique? The first, and most obvious one, is that of memory usage. With a large network, keeping a path table for each bot in the world will often be totally unfeasible. The optimisation I'd probably go for is to try and find ways to group the bots into 'squads,' and have each squad share a path table. Bear in mind, though, that very often a bot won't get round to exploring an entire network - they might be constrained to specific area, either by artificial constraints ('stay within radius' rules), or by their part of the network simply being isolated with no entry/exit routes (for example, in a set of rooms which the player reaches through the ventilation ducts).<br />
<br />
 If there are no constraints, then the tables could get quite large. However, the only time I could see a bot having no constraints would be if the bot were a 'principal character' of some sort - and you don't tend to have many of them, so the problem solves itself.<br />
<br />
 <br />
<strong class='bbc'>Progressive nets and subnets</strong><br />
 Another problem people emailed me about was using networks over large worlds. Not necessarily large networks; just networks which needed to cover large distances. Particularly over open terrain (Delta Force type worlds).<br />
<br />
 I think I have a solution which will help some people out. It also applies to some other situations too; large worlds with many enclosed spaces, for example.<br />
<br />
 Here we go: split nodes into 'levels.' That is, have a top level (level 0) which contains a 'general' set of nodes - nodes which cover most of the world, but are very coarse. The routes between them are like Interstate roads.<br />
<br />
 Into the next level, you put nodes which, while not totally in-depth, are more detailed than the Level 0 nodes. These are like your main roads. What's more, you give each Level 1 node a list of 'parent' Level 0 nodes. If you had an area of the world enclosed by routes between 4 Level 0 nodes, the Level 1 nodes inside the enclosure would have the 4 Level 0 nodes as parents. The Level 0 nodes, in return, keep lists of all Level 1 nodes which have them as parents. This means that you can take any given Level 0 node, and load into memory all 'nearby' Level 1 nodes.<br />
<br />
 This goes on for as many levels as you want (is 'progressive'), right until you're down to the small routes which are like people's driveways. Each level (excluding Level 0 and the smallest level) has lists of both parent and child nodes. So, from anywhere in the world, you can follow a node back to the 'interstate,' use the Level 0 nodes to get near to your destination, and then progressively use smaller and smaller levels to get closer and closer to your destination.<br />
<br />
 There are routes between nodes in any given level and the nodes in the level above - Level 1 is 'anchored' to Level 0 by such routes. So, only Level 0 is a complete network (in that of its routes and nodes are a part of it), unlike the other Levels which have dependencies on their parent levels.<br />
<br />
 This concept of Levels or 'sub-networks' can be extremely useful. Imagine a world containing many buildings which can be explored. The nodes in each building can be grouped into a subnet, and only loaded when the building is actually being traversed, saving large amounts of memory.<br />
<br />
 <br />
<strong class='bbc'>Echoes of the Past</strong><br />
 When tracking prey by scent, a predator will follow by picking up the scent and then continually checking in which direction the scent is strongest. If tracking is left too late, then the scent may have faded and so the prey cannot be tracked.<br />
<br />
 Here's an idea inspired by that. Have moving entities leave 'scents' in the network which can be followed by others. This would deal with the problem of tracking more than one moving target (the most recent scent would indicate the nearest entity), and the problem of an entity moving out of sight (perhaps even out of the network, if the 'education' technique is in use).<br />
<br />
 Give each node a list of pairs of entity IDs (or whatever) and timestamps. Then, whenever an entity visits a node (moves within a certain radius of it), either update the timestamp, or add it to the list if it not already present.<br />
<br />
 When tracking by scent, the predator bot needs the entity ID of its prey (or some way of checking any entity ID to pick out interesting scents), and a node that the prey has visited. Then, it searches all connected nodes, and finds the node with the most recent timestamp for the given entity ID. It moves to that node.<br />
<br />
 There's also a certain amount of clean-up that needs to be performed, too. Looking back to our original inspiration, a scent 'fades' after a certain amount of time. Once a scent has faded, it needs to be removed (well, it does if you don't want to run out of memory). Rather than checking the entire network for 'expired' scents frequently, we only need to ensure that the nodes we're processing are up-to-date - so, the scent list only needs to be cleaned up when it's being examined. As a result, the number of nodes you process is proportional to the number of entities in the network, rather than the size of the network.<br />
<br />
 Why use timestamps rather than a simple decrementing counter? Because a decrementing counter still needs to be decremented. Every game loop, you'd have to process the entire network, decrementing all the counters - and that's one heck of a performance hit, especially for a large network. When you take into account that many nodes may not have scents attached to them anyway, it is obviously inefficient. Timestamps only need to be calculated once, and are unchanging (until they are updated or removed); they're also much more versatile, in that different entities can use them in different ways. A decrementing counter only tells you how many iterations are left until the scent disappears; a timestamp, on the other hand, tells you how long the scent has been there, too.<br />
<br />
 There's a whole bunch more variations on this theme. Firstly, playing the with 'fade times' is definitely a good idea. Different scents could linger for different times; different predator bots could have their own 'threshold' values (for example, a bot tracking by sight rather than smell would have a fairly small time threshold). That does create a problem with cleanup - you can't be sure that a scent has faded to a point that no entity will detect it - but simply picking a sensibly large 'threshold' value should ensure that no entity is 'robbed' of the scent. It's a trade-off - the larger the value, then the surer you can be that entities will be able to pick up scents properly, but the more memory you use.<br />
<br />
 Also, be aware of movement speeds; when presented with two scents, the more recent of the two doesn't necessarily mean the nearest, because the more recent entity might move many times faster than the less recent, and so might be further away.<br />
<br />
 Finally, linking fade times into the nodes themselves could be very interesting, as I hinted at earlier. Perhaps nodes in a small river would have much quicker fade times - any predator tracking to the river would lose the scent, unless the prey had entered the river very recently.<br />
<br />
 <br />
<strong class='bbc'>Conclusion</strong><br />
 I hope you've figured out by now that you can attach pretty much any information to a node - be it a 'scent,' a mood, a warning, a reference number... you name it. And much of that information is static, and can be precalculated - found by a compiler tool, stored to a file, and then loaded and decompressed for instant use in-game. The network can be used not just for finding a route, but for deciding whether to use it.<br />
<br />
 Whenever you work with node networks like these, remember your constraints:<br />
<br />
 <ul class='bbc'><li>Minimise memory usage, mainly through minimising duplication of information. </li><li>Process nodes 'on-demand,' rather than forcing the whole network to be processed frequently. </li><li>Keep good connectivity in your game worlds to make the networks efficient. </li><li>Don't be afraid to use the network for more than just pathfinding.</li></ul> I think I've covered everything I wanted to cover. Feel free to email me at <a href='mailto:rfine@tbrf.net' title='E-mail Link' class='bbc_email'>rfine@tbrf.net</a> - I'll be happy to answer questions, discuss problems, and merely hear about how you're using the technique and how it's working for you. So.. until next time...<br />
<br />
]]></description>
		<pubDate>Mon, 12 May 2003 01:40:54 +0000</pubDate>
		<guid isPermaLink="false">412f1f1340a245ffec9fb8d47654da57</guid>
	</item>
	<item>
		<title>Implementing a Blackboard-like System for Squad...</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/implementing-a-blackboard-like-system-for-squad-r1931</link>
		<description><![CDATA[<span style='font-size: 18px;'><strong class='bbc'>I. Introduction</strong></span><br />
<br />
Artificial intelligence is fast becoming of primary importance for game developers as graphics hardware becomes faster and more commonplace and programmers begin to have more free processing power with which to make their games smarter and more believable. As a result, there are a large number of different types and styles of artificial intelligence that are being explored in game design terms which previously were thought to be primarily the realm of scientists working in laboratories on supercomputers.<br />
<br />
 One of these methods is the blackboard system. A blackboard system is one which takes inputs from a number of other artificial intelligence systems, processes those inputs, and then allows each of those systems to contribute their actions or inputs towards a common goal [McManus, 1992; GameAI]. This would be an almost perfect system to use for coordinating intelligent units in a combat situation.<br />
<br />
 Although this method has been used by major corporations and is currently being marketed as part of several business solutions, it is extremely complex and very difficult to implement from a design perspective; given the already extreme complexity of designing, creating, and managing (not to mention debugging) a game, it has so far been beyond the reach of game designers. AI programmers working on Close Combat [GameAI], for instance, initially intended to use such a system, but the complexity of it outstripped their time and resources. The system that eventually resulted from their labors was almost certainly the best artificial intelligence system to that point ever to grace a squad-level game, but the question of how much better it would have been had they been able to follow their vision is a tempting one. Certainly, the system might have benefited.<br />
<br />
 In this article, I will deal with the problem of implementing a simple blackboard system for use in a squad-level simulation taking place in real time. This technique is also applicable to the needs of turn-based games, but the designer then would have more freedom to expand the system; a real-time system forces us to constrain ourselves in our use of artificial intelligence, and to optimize as much as possible. Most importantly, however, a real-time system means that our decision-making processes, separate from the meat of the artificial intelligence, must be very fast to better mimic reality and enhance the suspension of disbelief.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>II. Structure</strong></span><br />
<br />
The structure of our system is of paramount importance; it will determine whether we, down the road, will be able to extensively modify our system if necessary *without* recoding every part of the system. We can ensure this by introducing a great deal of modularity into the classes and structures that we create. This will also help with debugging and optimization.<br />
<br />
 The primary pieces of the structure in the implementation explained in this article are as follows: units, contributions, and circumstances. I have delineated the relationship between these different portions below and specified the names by which I will be calling these different components; I will explain them further in a moment.<br />
<br />
<table border="1" cellpadding="5" cellspacing="0"> <tbody><tr> <td class="tblhdr"><strong class='bbc'>Units</strong></td><td class="tblhdr"><strong class='bbc'>Contribution</strong></td><td class="tblhdr"><strong class='bbc'>Circumstantially motivated?</strong></td>  </tr> <tr> <td> Soldiers <br>Squads <br>Platoons <br>Commander </td> <td> Actions <br>Thoughts <br>Thoughts II <br>Strategies </td>   <td> Very Heavily - all of the time <br>Heavily - very often <br>Occasionally <br>Only when necessary </td> </tr> </tbody></table><span style='font-size: 12px;'><strong class='bbc'>a. Units</strong></span><br />
<br />
 In this case, Soldier refers to the individual men and women that are being simulated on the battlefield. Squad refers to any grouping of soldiers, large or small - a machine gun crew would be a squad, as well as a full-fledged rifle squad. Platoon refers to a grouping of squads under a central command, and the Commander is the overall decision-maker. Each of these units represents a different artificial intelligence system: Soldiers are finite-state machines (FSM), Squads operate on the principle of fuzzy logic, and Platoons use both fuzzy logic and a higher-order FSM. The Commander in this case is our blackboard system.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>b. Contributions</strong></span><br />
<br />
Contributions are those pieces of the situational puzzle that are supplied by a particular level of organization. Actions are the simplest. Firing a weapon, walking, and taking cover are all actions: they have a simple definition, they represent a single process of survival for the Soldier, and they are the building blocks for every larger scale maneuver in the game.<br />
<br />
 Thoughts are a different matter altogether. A thought can be more easily referred to as a strategy; in this case, however, the words "thought" and "strategy" represent different concepts, so keep that in mind. A thought represents something actually running through the mind of a soldier, most likely a squad or team leader. This leader needs to decide how best to react when something happens, like his team or squad being flanked by a large number of soldiers, or when a nearby team moves out to storm a farmhouse.<br />
<br />
 All of the things that happen during or immediately prior to this period of thought - a large force of enemy soldiers flanks the leader's team, a machine gun opens fire to their front, a friendly team arrives and suppresses the machine gun - all help the leader formulate his plan of action. If the things that happen match (or come close to) something that the leader already has an experience of, and the leader knows what actions will likely keep his team safe, he will attempt to carry out those actions. If this has never happened before, he will need to come up with a new way to react, based on his best guess of what will work. If the new way works, he will remember this experience the next time. If an old way works, he will be more confident in its usage. All of these things are represented in the fuzzy-logic-based squad AI model; read the implementation section for an explanation of how this works.<br />
<br />
 The combination of fuzzy logic and a high-order finite state machine at the platoon level come into play when the pre-defined actions and objectives available to a platoon leader (attack that hill, retreat, suppress, implement fire and maneuver) are combined with the leader's knowledge of previous situations and the weight he gives to his memory of things that have worked. Whereas a squad would simply process what was going on and make a decision based on what should work best and what orders they are currently under, a platoon leader has a much more vested interest in maintaining simplicity on the battlefield - formations are not just good ways to better engage the enemy, they are good ways to ensure that the platoon leader knows where everybody is. The platoon leader has to deal with a wider area of situational awareness. However, it also does him/her much good to remember past situations and apply them to the present, as real humans do. Therefore, the AI for the platoon leader represents not just a memory of things that worked and objectives, but a desire to maintain as much form and order as possible on the battlefield. A squad leader might not have time to worry about exactly where he is on the battlefield in relation to another platoon; that's not his job. It is, however, the platoon leader's.<br />
<br />
 The strategies of the Commander, on the other hand, involve not simply making a decision; just giving his troops an objective and then walking away wouldn't be a very effective or efficient way for a commander at the company/task force level to run a battle. Instead, the commander takes what all of his men are telling him (both with their reports (platoons) and with the actions that they take (squads)) and turns that into a successful battle. If, for instance, a platoon has attempted to assault a pair of buildings and the commander notes that two of the squads involved are currently spending their time finding cover rather than attacking, he most likely would decide to support the attacking units with more suppressive fire. If, at the same time an enemy force attacked another of his platoons, however, the commander would likely order the assaulting platoon to withdraw and commit his reserves against the attacking enemy force.<br />
<br />
 Now, what if the commander has an urgent objective? What if a bridge elsewhere needs to be taken immediately, regardless of loss? The commander, unlike the platoon or squad, has to deal with large numbers of what-ifs. Although certainly applicable, situations are unlikely to completely reproduce themselves for the commander. A squad might face the same type of situation repeatedly. In a fluid battle, this is unlikely to happen to the commander, and it might even be unprofitable for him to waste time thinking about whether or not anything he has done has fit the situation he is currently in.<br />
<br />
 In addition, more often than not, the people under the commander are not contributing to the overall solution unless the commander has resolved exactly what that solution is. The chances of a unit wasting their time are high; they do not know, nor are they required to know, what else is going on. It is the commander's job to make all of these units work together, and to ensure that a solution a) has been found and b) has a high likelihood of success.<br />
<br />
 It is in the commander's best interests not to micro-manage; his squad leaders know what they're doing when put in the proper place, and even the actions of his platoons are best controlled by his platoon leaders. However, by formulating and imposing his solution upon these units, rather than by controlling them or giving them direct orders, the units have a *much* higher likelihood of carrying out their duties in a useful manner, and the commander has a much better chance of winning the battle. He needs to tell his troops what to win, not how to win it.<br />
<br />
 This concept is perfectly represented by a blackboard system; the input from the units flows in, and ideally a solution is produced. This solution involves: a) a list of objectives, b) a list of threats, c) a list of units in trouble, and d) a list of units capable of providing support. How the units go about solving this problem is their own matter - a large number of sub-problems. What the commander does is make sure that they coordinate their actions according to the large problem or, if you will, the "big picture."<br />
<br />
<span style='font-size: 12px;'> <strong class='bbc'>c. Circumstances</strong></span><br />
<br />
Circumstances are simultaneously the most and least important things on the battlefield. A circumstance is anything that is happening that can be defined as a concept - being flanked, being surrounded, having the advantage over visible enemies. These circumstances happen primarily to squads: a platoon may be flanked, but it is more likely that one or two of its squads have been flanked, while the other one or two might be able to maneuver, fire, or extract themselves. Further up in the level of organization, the Commander has little chance of being effected by circumstances. The Commander may not care whether a squad has been flanked. His solution may involve that squad holding its position at all costs. If his solution involves that squad both surviving and attacking a position, he might reformulate the solution to deal with the fact that that squad cannot move, or to deal with the flanking enemy directly. He might, for instance, move that unit up on the priority list of units in trouble, causing other units able to support to move to help. He might also increase the threat level registered for the flanking force. All of these things are not direct orders to his units -- they are changes to the current solution.<br />
<br />
 Meanwhile, squads and especially soldiers are profoundly affected by circumstances. To use a popular reference, even though the overall strategy of delaying the enemy was for the most part working, the fact that the sniper and his supporting machine gun could not easily displace in the movie Saving Private Ryan meant that they were quickly killed. The battle continued; the commander altered his solution and things worked again for a while. The circumstances that ended the lives of three men had little direct effect on the battle as a whole.<br />
<br />
 Eventually, of course, circumstances caught up with that commander, and the battle was lost (save for the miraculous arrival of attack planes and a large number of soldiers coming from who knows where). In the end, the commander himself was killed, but by that point, the battle had been lost for several minutes, due to poor circumstances affecting everyone in his command. In a sense the commander himself, when he stopped directing the battle (I would say around the part when he and Matt Damon started using mortar shells like hand grenades), became a soldier and allowed himself to be influenced by circumstance.<br />
<br />
 A rifleman has no idea what another platoon's machine gun is doing. He knows that there are enemy machine guns in front of him, and that he has little cover. He relies on the squad leader to find the best cover for him, or at best to get him out of the situation, but he also knows that if he lies down flat and tries to hide, he has a better chance of not being shot.<br />
<br />
 The squad leader, likewise, probably has little idea of the other happenings on the larger battlefield. He knows that he has a good chance of getting his squad to good cover if he moves to the left and into the trees. He relies on the platoon leader to communicate to him what objectives he should be taking. However, the squad leader is also aware that regardless of what needs to be done, his people need cover. (The squad leader's actions then communicate to the Commander that more support is needed in that sector, or that the objective needs to be changed.)<br />
<br />
 Lastly, the platoon leader is sometimes affected by circumstances - for instance, he himself may discover that he has been flanked. As he is less of an immediate threat than, say, a machine gun, however, it is likely that the enemy will attempt first to destroy his soldiers' ability to fight. The platoon leader relies on the commander to provide him with the information he needs from other units to influence the battle positively.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>d. Conclusion</strong></span><br />
<br />
All of these elements of the AI structure have the ability to come together and form the basis for a very intelligent means of carrying out a battle. If properly implemented, they create a force that is capable of learning from its mistakes, remembering its successes, and acting based on a strategy that takes into account the situation of all forces involved. In the next section, I will explore the implementation of this system.]]></description>
		<pubDate>Sun, 27 Apr 2003 13:47:49 +0000</pubDate>
		<guid isPermaLink="false">0b36451530d9491114523d4b66253837</guid>
	</item>
	<item>
		<title>Chess Programming Part VI: Evaluation Functions</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/chess-programming-part-vi-evaluation-functions-r1208</link>
		<description><![CDATA[It's been six months, and I know sometimes it must have felt like I would never shut up, but here we are: the sixth and last installment of my chess programming series. Better yet: my Java chess program (see attached resource file), primitive though it may be, is now complete, and I shipped it to Gamedev along with this, which proves that I know (a little bit of) what I've been talking about.<br />
<br />
 This month's topic, the evaluation function, is unique in a very real sense: while search techniques are pretty much universal and move generation can be deducted from a game's rules and no more, evaluation requires a deep and thorough analysis of strategy. As you can well imagine, it is impossible to assess a position's relative strengths if we don't know what features are likely to lead to victory for one player or the other. Therefore, many of the concepts discussed here may apply to other games in very different fashion, or not at all; it is your job as programmer to know your game and decide what the evaluator should take into consideration.<br />
<br />
 Without further delay, let us take a look at some board evaluation metrics and at how they can be used to evaluate a chess position.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Material Balance</strong></span><br />
<br />
To put it simply, material balance is an account of which pieces are on the board for each side. According to chess literature, a queen may be worth 900 points, a rook 500, a bishop 325, a knight 300 and a pawn 100; the king has infinite value. Computing material balance is therefore a simple matter: a side's material value is equal to<br />
<br />
<p class='bbc_center'> MB = Sum( Np * Vp )<br />
</p><br />
 where Np is the number of pieces of a certain type on the board and Vp is that piece's value. If you have more material on the board than your opponent, you are in good shape.<br />
<br />
 Sounds simple, doesn't it? Yet, it is by far the overwhelming factor in any chess board evaluation function. CHESS 4.5's creators estimate that an enormous advantage in position, mobility and safety is worth less than 1.5 pawns. In fact, it is quite possible to play decent chess without considering anything else!<br />
<br />
 Sure, there are positions where you should sacrifice a piece (sometimes even your queen) in exchange for an advantage in momentum. These, however, are best discovered through search: if a queen sacrifice leads to mate in 3 moves, your search function will find the mate (provided it looks deep enough) without requiring special code. Think of the nightmares if you were forced to write special-case code in your evaluator to determine when a sacrifice is worth the trouble!<br />
<br />
 Few programs use a material evaluation function as primitive as the one I indicated earlier. Since the computation is so easy, it is tempting to add a few more features into it, and most people do it all the time. For example, it is a well-known fact that once you are ahead on material, exchanging pieces of equal value is advantageous. Exchanging a single pawn is often a good idea, because it opens up the board for your rooks, but you would still like to keep most of your pawns on the board until the endgame to provide defense and an opportunity for queening. Finally, you don't want your program to panic if it plays a gambit (i.e., sacrifices a pawn) from its opening book, and therefore you may want to build a "contempt factor" into the material balance evaluation; this allows your program to think it's ahead even though it is behind by 150 points of material or more, for example.<br />
<br />
 Note that, while material balance is highly valuable in chess and in checkers, it is deceiving in Othello. Sure, you must control more squares than the opponent at the end of the game to win, but it is often better to limit his options by having as few pieces on the board as possible during the middlegame. And in other games, like Go-Moku and all other Connect-N variations, material balance is irrelevant because no pieces are ever captured.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Mobility and Board Control</strong></span><br />
<br />
One of the characteristics of checkmate is that the victim has no legal moves left. Intuitively, it also seems better to have a lot of options available: a player is more likely to be able to find a good line of play if he has 30 legal moves to choose from than if he is limited to 3.<br />
<br />
 In chess, mobility is easily assessed: count the number of legal moves for each side given the position, and you are done. However, this statistic has proven to be of little value. Why? For one thing, many chess moves are pointless. It may be legal to make your rook patrol the back rank one square at a time, but it is rarely productive. For another, trying to limit the opponent's mobility at all costs may lead the program to destroy its own defensive position in search of "pointless checks": since there are rarely more than 3-4 legal ways to evade check in any given position, a mobility-oriented program would be likely to make incautious moves to put the opponent in check, and after a while, it may discover that it has accomplished nothing and has dispersed its forces all over the board.<br />
<br />
 Still, a few sophisticated mobility evaluation features are always a good thing. My program penalizes "bad bishops", i.e., bishops whose movement is hampered by a large number of pawns on squares of the same color, as well as knights sitting too close to the edges of the board. As another example, rooks are more valuable on open and semi-open files, i.e., files where there are no pawns (or at least no friendly ones).<br />
<br />
 A close relative of mobility is board control. In chess, a side controls a square if it has more pieces attacking it than the opponent. It is usually safe to move to a controlled square, and hazardous to move to one controlled by the opponent. (There are exceptions: moving your queen to a square attacked by an enemy pawn is rarely a good idea, no matter how many ways you can capture that pawn once it has done its damage. You may also voluntarily put a piece in harm's way to lead a defender away from an even more valuable spot.) In chess, control of the center is a fundamental goal of the opening. However, control is somewhat difficult to compute: it requires maintaining a database of all squares attacked by all pieces on the board at any given time. Many programs do it; mine doesn't.<br />
<br />
 While mobility is less important than it seems to the chess programmer, it is extremely important in Othello (where the side with the fewest legal moves in the endgame is usually in deep trouble). As for board control, it is the victory condition of Go.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Development</strong></span><br />
<br />
An age-old maxim of chess playing is that minor pieces (bishops and knights) should be brought into the battle as quickly as possible, that the King should castle early and that rooks and queens should stay quiet until it is time for a decisive attack. There are many reasons for this: knights and bishops (and pawns) can take control of the center, support the queen's attacks, and moving them out of the way frees the back rank for the more potent rooks. Later on in the game, a rook running amok on the seventh rank (i.e., the base of operations for the opponent's pawns) can cause a tremendous amount of damage.<br />
<br />
 My program uses several factors to measure development. First, it penalizes any position in which the King's and Queen's pawns have not moved at all. It also penalizes knights and bishops located on the back rank where they hinder rook movement, tries to prevent the queen from moving until all other pieces have, and gives a big bonus to positions where the king has safely castled (and smaller bonuses to cases where it hasn't castled yet but hasn't lost the right to do so) when the opponent has a queen on the board. As you can see, the development factor is important in the opening but quickly loses much of its relevance; after 10 moves or so, just about everything that can be measured here has already happened.<br />
<br />
 Note that favoring development can be dangerous in a game like Checkers. In fact, the first player to vacate one of the squares on his back rank is usually in trouble; avoiding development of these important defensive pieces is a very good idea.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Pawn Formations</strong></span><br />
<br />
Chess grandmasters often say that pawns are the soul of the game. While this is far from obvious to the neophyte, the fact that great players often resign over the loss of a single pawn clearly indicates that they mean it!<br />
<br />
 Chess literature mentions several types of pawn features, some valuable, some negative. My program looks at the following:<br />
 <ul class='bbc'><li> Doubled or tripled pawns. Two or more pawns of the same color on the same file are usually bad, because they hinder each others movement.</li><li> Pawn rams. Two opposing pawns "butting heads" and blocking each others forward movement constitute an annoying obstacle.</li><li> Passed pawns. Pawns which have advanced so far that they can no longer be attacked or rammed by enemy pawns are very strong, because they threaten to reach the back rank and achieve promotion.</li><li> Isolated pawns. A pawn which has no friendly pawns on either side is vulnerable to attack and should seek protection.</li><li> Eight pawns. Having too many pawns on the board restricts mobility; opening at least one file for rook movement is a good idea.</li></ul> A final note on pawn formations: a passed pawn is extremely dangerous if it has a rook standing behind it, because any piece that would capture the pawn is dead meat. My program therefore scores a passed pawn as even more valuable if there is a rook on the same file and behind the pawn.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>King Safety and Tropism</strong></span><br />
<br />
We have already touched on king safety earlier: in the opening and middle game, protecting the king is paramount, and castling is the best way to do it.<br />
<br />
 However, in the endgame, most of the pieces on both sides are gone, and the king suddenly becomes one of your most effective offensive assets! Leaving him behind a wall of pawns is a waste of resources.<br />
<br />
 As for "tropism", it is a measure of how easy it is for a piece to attack the opposing king, and is usually measured in terms of distance. The exact rules used to compute tropism vary by piece type, but they all amount to this: the closer you are to the opposing king, the more pressure you put on it.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Picking the Right Weights</strong></span><br />
<br />
Now that we have identified the features we would like to measure, how do we assign relative weights to each?<br />
<br />
 That, my friends, is a million-dollar question. People can (and do) spend years fiddling with the linear combination of features in their evaluation functions, sometimes giving a little more importance to mobility, sometimes de-emphasizing safety, etc. I wish there were an absolute solution, but there isn't. This is still very much a matter for trial and error. If your program plays well enough, great. If not, try something else, and play it against the old version; if it wins most of the time, your new function is an improvement.<br />
<br />
 Three things you may want to keep in mind:<br />
 <ul class='bbc'><li> It is very difficult to refine an evaluation function enough to gain as much performance as you would from an extra ply of search. When in doubt, keep the evaluator simple and leave as much processing power as possible to alphabeta.</li><li> Unless you are after the World Championship, your evaluator does not need to be all-powerful!</li><li> If your game plays really fast, you may want to try evolving an appropriate evaluator using a genetic algorithm. For chess, though, this would likely require thousands of years!</li></ul> <br />
<span style='font-size: 18px;'><strong class='bbc'>Next Month</strong></span><br />
<br />
Well, there ain't no next month. This is it.<br />
<br />
 If I wanted to drag this series even longer, I could write about opening books, endgame libraries, specialized chess hardware and a zillion other things. I could, I could. But I won't. Some of these topics I reserve for the book chapter I will be writing on this very topic later this Fall. Others I just don't know enough about to contribute anything useful. And mostly, I'm just too lazy to bother.<br />
<br />
 Still, I hope you enjoyed reading this stuff, and that you learned a useful thing or two or three. If you did, look me up next year at the GDC or at E3, and praise me to whomever grants freelance design and programming contracts in your company, will ya?<br />
<br />
 Cheers!<br />
<br />
<br />
<em class='bbc'> François Dominic Laramée, October 2000</em>]]></description>
		<pubDate>Sun, 08 Oct 2000 22:07:23 +0000</pubDate>
		<guid isPermaLink="false">bea5b83d3a056039813089e7aa7f7e9a</guid>
	</item>
	<item>
		<title>Chess Programming Part V: Advanced Search</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/chess-programming-part-v-advanced-search-r1197</link>
		<description><![CDATA[Hey, it looks like there are dozens (and dozens) of you reading this series!  I'm tickled pink!<br />
<br />
 In this next-to-last article, we will examine advanced search-related techniques which can speed up and/or strengthen your chess-playing program.  In most cases, the concepts (if not the actual code) also apply to a variety of other 2-player games; adapting them to your particular problem, however, shall remain an exercise for the proverbial reader.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Why Bother?</strong></span><br />
<br />
So far, all of the search algorithms we have looked at examine a position's consequences to a fixed "depth".  However, this is rarely a good thing.  For example, suppose that your program uses an iterative-deepening alpha-beta algorithm with maximum depth 5-ply.  Now look at these cases:<br />
 <ul class='bbc'><li>Along a certain line of play, you discover a position where one of the players is checkmated or stalemated at depth 3.  Obviously, you don't want to keep searching, because the final state of the game has been resolved.  Not only would searching to depth 5 be a colossal waste of effort, it may also allow the machine to finagle its way into an illegal solution!</li><li>Now, suppose that, at depth 5, you capture a pawn.  The program would be likely to score this position in a favorable light, and your program might decide that the continuation leading to it is a useful one.  However, if you had looked one ply further, you might have discovered that capturing the pawn left your queen undefended.  Oops.</li><li>Finally, suppose that your queen is trapped.  No matter what you do, she will be captured by the opponent at ply 4, except for one specific case where her death will happen at ply 6.  If you search to depth 5, the continuations where the queen is captured at ply 4 will be examined accurately, and scored as likely disasters.  However, the unique line of play where the queen is only captured at ply 6 (outside of the search tree) doesn't reveal the capture to the machine, which thinks that the queen is safe and gives it a much better score!  Now, if all you have to do to push the queen capture outside of the search tree is delay the opponent with a diversion, doing so may be worth the risk: although it could damage your position, it might also cause the opponent to make a mistake and allow the queen to escape.  But what if you can only delay the queen capture by sacrificing a rook?  To the machine, losing a rook at ply 4 is less damaging than losing a queen, so it will merrily throw its good piece away and "hide" the too-horrible-to-mention queen capture beyond its search horizon.  (During its next turn, of course, the machine will discover that the queen must now be captured at ply 4 in all cases, and that it has wasted a rook for no gain.)  Hans Berliner described this "horizon effect" a long time ago, and it is the most effective justification for the "quiescence search" described in the next section.</li></ul> The bottom line is this: a great many positions in chess (and in other games as well) are just too chaotic to be evaluated properly.  An evaluation function can only be applied effectively to "quiet" positions where not much of importance is likely to happen in the immediate future.  How to identify these is our next topic.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Quiet, Please!</strong></span><br />
<br />
There are two ways to assess a position's value: dynamic evaluation (i.e., look at what it may lead to) and static evaluation (i.e., see what it looks like on its own, irrespective of consequences).  Dynamic evaluation is performed through search; as we have just mentioned, static evaluation is only feasible when the position is not likely to undergo an overwhelming change of balance in the near future.  Such relatively stable positions are called "quiet" or "quiescent", and they are identified via "quiescence search".<br />
<br />
 The basic concept of Quiescence Search is the following: once the program has searched everything to a fixed depth (say, 6-ply), we continue each line of play selectively, by searching "non-quiescent" moves only, until we find a quiescent position, and only then apply the evaluator.<br />
<br />
 Finding a quiet position requires some knowledge about the game.  For example, which moves are likely to cause a drastic change in the balance of power on the board?  For chess, material balance tends to be the overwhelming consideration in the evaluator, so anything that changes material is fair game: captures (especially those of major pieces) and pawn promotions certainly qualify, while checks may also be worth a look (just in case they might lead to checkmate).  In checkers, captures and promotions also seem like reasonable choices.  In Othello, every single move is a capture, and "material balance" can change so much in so little time that it might be argued that there are no quiet positions at all!<br />
<br />
 My own program uses a simple quiescence search which extends all lines of play (after a full-width search to depth X) by looking exclusively at captures.  Since there are usually not that many legal captures in a given position, the branching factor in the quiescence search tends to be small (4-6 on average, and quickly converging to 0 as pieces are eaten on both sides).  Nevertheless, the quiescence search algorithm is called on a LOT of positions, and so it tends to swallow 50% or more of the entire processing time.  Make sure that you need such a scheme in your own game before committing to it.<br />
<br />
 Only when no capture is possible does my program apply its evaluator.  The result is a selectively-extended search tree which is anything but fixed-depth, and which defeats most of the nasty consequences of the "horizon effect".<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>The All-Important Null-Move</strong></span><br />
<br />
One of the most effective ways to speed up a chess program is to introduce the concept of a null move into the equation.<br />
<br />
 The null move consists, quite simply, of skipping a turn and letting the opponent play two moves in a row.  In the overwhelming majority of positions, doing nothing is a bone-head idea: you should (almost) always be able to do *something* to improve your lot.  (To be honest, there are a few "damned if I do, damned if I don't" positions where the null move would actually be your best bet, and the computer will not play them correctly, but such "zugzwang" positions are hopeless anyway, so the loss of performance is not very traumatic.)<br />
<br />
 Allowing the computer to try a null move during search has several advantages related to speed and accuracy.  For example:<br />
 <ul class='bbc'><li>Suppose that a position is so overwhelmingly in your favor that, even if you skipped your turn, the opponent couldn't respond with anything that would help.  (In program terms, you would get a beta cutoff even without making a move.)  Suppose further that this position is scheduled to be searched to depth N.  The null move, in effect, takes out an entire ply of the search tree (you are searching only the null move instead of all your legal ones) and if your branching factor is B, searching the null move is equivalent to looking at a single depth N-1 subtree instead of B of them.  With B=35 as in the typical chess middlegame, null-move search may only consume 3% of the resources required by a full depth-N examination.  If the null move search reveals that you are still too strong even without playing (i.e., it creates a cutoff), you have saved 97% of your effort; if not, you must examine your own legal moves as usual, and have only wasted an extra 3%.  On average, the gain is enormous.</li><li>Now, suppose that, during quiescence search, you reach a position where your only legal capture is rook-takes-pawn, which is immediately followed by the opponent's knight-takes-rook.  You'd be a lot better off not making the capture, and playing any other non-capture move, right?  You can simulate this situation by inserting the null move into the quiescence search: if, in a given position during quiescence search, it is revealed that the null move is better than any capture, you can assume that continuing with captures from this position is a bad idea, and that since the best move is a quiet one, this is a position where the evaluation function itself should be applied!</li></ul> Overall, the null-move heuristic can save between 20% and 75% of the effort required by a given search.  Well worth the effort, especially when you consider that adding it to a program is a simple matter of changing the "side to play" flag and adding less than a dozen lines of code in the quiescence search algorithm!<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Aspirated Search and MTD(f)</strong></span><br />
<br />
Plain old alphabeta assumes nothing about a position's ultimate minimax value.  It looks at *everything*, no matter how preposterous.  However, if you have a pretty good idea of what the value will turn out to be (for example, because you are running an iterative-deepening scheme and have received the previous iteration's results), you might be able to identify lines of play that are so out of whack with your expectations that they can't possibly be right, and cut them off pre-emptively.<br />
<br />
 For example, suppose that you have reason to believe that a position's value will be close to 0, because it is very well balanced.  Now, suppose that an internal node's preliminary evaluation is at +20,000.  You can cutoff with reasonable confidence.<br />
<br />
 This is the idea behind "aspiration search", a variant of alphabeta in which, instead of using +INFINITY and -INFINITY as the initial bounds of the search, you set a small window around the expected value instead.  If the actual value happens to fall within the window, you win: you'll get it without error, and faster than you would otherwise (because of the many extra cutoffs).  If not, the algorithm will fail, but the error will be easy to detect (because the minimax value you'll receive will be equal to one of the bounds); you'll have to waste a bit of time re-searching with a wider wind&#111;w.  If the former case happens more often than the latter, you win on average.  Obviously, the better your initial guess of the expected value, the more useful this technique is.<br />
<br />
 In the mid 1990's, researcher Aske Plaat extended aspiration search to its logical conclusion: what if you called an aspirated alphabeta with a search window of width equal to zero?  It would fail all the time, of course...  But it would do so *very quickly*, because it would cutoff every path almost immediately.  Now, if the failure indicates that the actual value is lower than your estimate, you can try again, with another zero-width window around a smaller estimate, etc.  In a sense, you could then use alphabeta to perform a binary search into the space of all possible minimax values, until you reach the only call which will *not* fail because the zero-width window will be centered on the position's actual value!<br />
<br />
 This brilliant idea, presented in a paper available on the web at <a href='http://theory.lcs.mit.edu/%7Eplaat/mtdf.html' class='bbc_url' title='External link' rel='nofollow external'>http://theory.lcs.mi...plaat/mtdf.html</a>, has been embodied in the MTD(f) search algorithm, which is all of 10 lines long.  Tacked on top of an alphabeta implementation equipped with a transposition table, MTD(f) is incredibly efficient and highly parallel-friendly.  It also works better with "coarse-grain" (and therefore probably simpler and faster) evaluators: it is easy to see that it takes fewer probes to zero in on the actual value in a binary search if the smallest "atom" of value is equal to, say, 0.1 pawns rather than 0.001 pawns.<br />
<br />
 There are other alphabeta variants in wider use (namely, the infamous NegaScout; I would rather teach General Relativity to orangutangs than get into that mess) but Plaat insists that MTD(f) is the most efficient algorithm in existence today and I'll take his word for it.  My own program uses MTD(f); you'll be able to marvel at the algorithm's simplicity very shortly!<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Singular Extensions</strong></span><br />
<br />
One last thing before we leave the topic of search: in chess, some moves are obviously better than others, and it may not be necessary to waste too much time searching for alternatives.<br />
<br />
 For example, suppose that after running your iterative algorithm to depth N-1, you discover that one of your moves is worth +9000 (i.e., a capture of the opponent's queen) and all others are below 0.  If saving time is a consideration, like in tournaments, you may want to bypass the whole depth N search and only look at the best move to depth N instead: if this extra ply does not lower its evaluation much, then you assume that the other moves won't be able to catch up, and you stop searching early.  (Remember: if there are 35 valid moves at each ply on average, you may have just saved 97% of your total effort!)<br />
<br />
 Deep Blue's team has pushed this idea one step further and implemented the concept of "singular extensions".  If, at some point in the search, a move seems to be a lot better than all of the alternatives, it will be searched an extra ply just to make sure that there are no hidden traps there.  (This is a vast oversimplification of the whole process, of course, but that's the basic idea.)  Singular extensions are costly: adding an extra ply to a node roughly doubles the number of leaves in the tree, causing a commensurate increase in the number of calls to the evaluator; in other words, Deep Blue's specialized hardware can afford it, my cranky Java code can't.  But it's hard to argue with the results, isn't it?<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Next Month</strong></span><br />
<br />
In Part VI, we wrap up the series with a discussion of evaluation functions, the code which actually tells your program whether a given board position is good or bad.  This is an immense topic, and people can (and do) spend years refining their own evaluators, so we will have to content ourselves with a rather high-level discussion of the types of features which should be examined and their relative importance.  If everything goes according to plan, I should also have some Java code for you to sink your teeth into at about that time, so stick around, won't you?<br />
<br />
<em class='bbc'> François Dominic Laramée, September 2000</em>]]></description>
		<pubDate>Wed, 06 Sep 2000 00:09:15 +0000</pubDate>
		<guid isPermaLink="false">ec47951a847319d0dd4933431b5b2c0f</guid>
	</item>
	<item>
		<title>Application of Genetic Programming to the Snake...</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/application-of-genetic-programming-to-the-snake-r1175</link>
		<description><![CDATA[<strong class='bbc'>Abstract:</strong> This paper describes the evolution of a genetic program to optimize a problem featuring task prioritization in a dynamic, randomly updated environment. The specific problem approached is the "snake game" in which a snake confined to a rectangular board attempts to avoid the walls and its own body while eating pieces of food. The problem is particularly interesting because as the snake eats the food, its body grows, causing the space through which the snake can navigate to become more confined. Furthermore, with each piece of food eaten, a new piece of food is generated in a random location in the playing field, adding an element of uncertainty to the program. This paper will focus on the development and analysis of a successful function set that will allow the evolution of a genetic program that causes the snake to eat the maximum possible pieces of food.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Introduction and Overview</strong></span><br />
<br />
Artificial intelligence (AI) techniques have been proven highly successful at the problems of navigation, task prioritization, and problem avoidance. Traditionally, humans have encoded rule-based AIs to create the behaviors necessary to allow an automaton to achieve a specific task or set of tasks. Genetic programming (GP), however, has been proven to allow a computer to create human-competitive results. Specifically, examples such as the wall-following robot (Koza 1992) and Pac Man® (Koza 1992) demonstrate the effectiveness of GP at evolving programs capable of navigation and task prioritization behaviors which are competitive with human-produced results.<br />
<br />
 In an original approach to demonstrating the effectiveness of GP at producing human-competitive results, this paper describes the evolution of a genetic program that can successfully achieve the maximum possible score in the "snake game." The problem posed by the snake game is of particular interest for two main reasons. First, the size and shape of the area through which the main game character, the snake, can move is constantly changing as the game progresses. Second, as the snake eats the single available piece of food on the game board, a new piece is generated in a random location. Because of these two factors, the snake game presents a unique challenge in the developing of a function and terminal set to allow GP to evolve an optimal solution that is generalized for successive runs of the snake game.<br />
<br />
 The "Background" section of this paper outlines the rules and discusses the specific details of the "snake game." Next, "Statement of the Problem" explains the problem being addressed by this paper. The "Methods" section provides the GP specifics of how the problem was approached. The "Results" section gives numerous examples of results produced by the GP runs along with a discussion and analysis of those results. The "Conclusion" section summarizes the ultimate results achieved by the paper. The "Future Work" section discusses potential for further study in line with the work discussed in this paper. Finally, the "References" section provides a bibliography for the paper.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Background</strong></span><br />
<br />
The "snake game" has been in existence for over a decade and seen incarnations on nearly every popular computing platform. The game begins with a snake having a fixed number of body segments confined to a rectangular board. With each time step that passes, the snake can either change direction to the right or left, or move forward. Hence the snake is always moving. Within the game board there is always one piece of food available. If the snake is able to maneuver its head onto the food, its tail will then grow by a single body segment and another piece of food will randomly appear in an open portion of the game board during the next time step. The game ends when the snake’s head advances into a game square that is filled with either a snake body segment, or a section of the wall surrounding the game board. From a task prioritization standpoint, then, the snake’s primary goal is to avoid running into an occupied square. To the extent that this first priority is being achieved, its second priority is to pursue the food.<br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[9a922287c5be49409fbe7d41fcd8edca]' id='ipb-attach-url-3156-0-65267600-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3156" title="image1.gif - Size: 4.73K, Downloads: 85"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-04096600-1308066089_thumb.gif" id='ipb-attach-img-3156-0-65267600-1330207785' style='width:250;height:184' class='attach' width="250" height="184" alt="Attached Image: image1.gif" /></a> </p><br />
The version of the game used for this paper, shown in figure 1, is a replica of the game as it currently exists on Nokia cell phones. In this version, which is available for play online at <a href='http://www.nokia.com/snake' class='bbc_url' title='External link' rel='nofollow external'>www.nokia.com/snake</a>, the game board is made up of 220 total squares, 20 horizontal and 11 vertical, and the food begins in position (11,6) on the game board, represented by a diamond in the figure. The snake is initially made up of 9 body segments, occupying positions (1,11)-(9,11) on the board, with the head in position (9,11) and the snake moving to the right, represented by the arrow in the figure. The maximum number of pieces of food that can be eaten is the size of the game board minus the initial size of the snake. With the given parameters, then, this equates to 220-9=211 pieces of food. This is because with each piece of food eaten, the snake grows by a body segment, reducing the amount of free space in which it can move. Hence when it has eaten 211 pieces of food, its body will fill the entire game board, rendering any further movement impossible. One critical piece of information is whether or not it is even possible for the snake to eat the maximum amount of food. Indeed it is conceivable that after eating a certain amount of food, the snake will have grown so large that it restricts itself from access to a portion of the board. Upon close inspection, however, the reader will note that by tracing certain patterns repeatedly over the board, it is possible for the snake to cover every square exactly once and return to its initial position. One such pattern is shown in figure 2, which features a snake of 210 body segments about to eat the final piece of food. Hence by continually tracing the pattern shown, the snake can eat the maximum possible pieces of food.<br />
<br />
  In evolving a genetic program to successfully eat the maximum amount of food, a human competitive solution, in terms of score, will have been obtained. With that in mind, there are some important differences in the game when being played by a human as opposed to a computer-generated program.<br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[9a922287c5be49409fbe7d41fcd8edca]' id='ipb-attach-url-3157-0-65289900-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3157" title="image2.gif - Size: 4.45K, Downloads: 105"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-94604500-1308066114_thumb.gif" id='ipb-attach-img-3157-0-65289900-1330207785' style='width:250;height:178' class='attach' width="250" height="178" alt="Attached Image: image2.gif" /></a></p><br />
 For a human player, the fact that the snake is always moving adds an element of pressure, forcing him/her to make decisions in a timely manner. When using a computer to play the game, this is not a concern, as the computer will have the time between each move to parse through a program tree and determine the next move. The nearest equivalent to "pressure" for a computer is any limitation imposed on the size and depth of the genetic program’s function tree. These limitations restrict the possible number of decision trees that can be generated, thereby ensuring that the computer will have a finite amount of time in which to determine the next move for the snake. The particular function tree limitations imposed for this problem will be discussed in the following "methods" section.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Statement of the Problem</strong></span><br />
<br />
The fundamental problem of the snake game is to eat the maximum number of food pieces before "dying" by running into either a wall or a segment of the snake’s body. The problem being addressed in this paper is to provide a function and terminal set that will allow for the evolution of a GP that will maximize the number of food pieces eaten by the snake. The maximum goal for the particular configuration of the snake game used in this paper is 211 pieces of food.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Methods</strong></span><br />
<br />
Table 1 provides the tableau for the initial runs of the snake game. Following over twenty initial runs of the program, the maximum score that had been achieved was 123 hits. As it was apparent that a maximum solution would not be obtained using the initial function set, the function set was expanded to enhance the snake’s movement and environment sensing capabilities. For the remainder of the paper, any GP runs performed with the function and terminal sets given in Table 1 will be referred to as a run made with the "initial" function set. Any run made with the enhanced function set, which includes the complete initial function set as a subset, will be referred to as having been made with the "final" function set. A discussion of both the initial and final function sets follows.<br />
<br />
<strong class='bbc'> Table 1. Tableau for Snake-Game Problem</strong><br />
<br />
<table width="543" border="1" cellpadding="7" cellspacing="1"><tbody><tr valign="top"><td width="23%">Objective:</td><td width="77%">Find a computer program that eats the maximum possible pieces of food.</td></tr><tr valign="top"><td>Terminal set:</td><td>(forward), (left), (right)</td></tr><tr valign="top"><td>Function set:</td><td>ifFoodAhead, ifDangerAhead, ifDangerRight, ifDangerLeft, progn2</td></tr><tr valign="top"><td>Fitness cases:</td><td>One fitness case.</td></tr><tr valign="top"><td>Raw Fitness:</td><td>Pieces of food eaten.</td></tr><tr valign="top"><td>Standardized fitness:</td><td>Maximum possible pieces of food eaten (211) minus the raw fitness.</td></tr><tr valign="top"><td>Hits:</td><td>Total pieces of food eaten during a run of the program, same as raw fitness.</td></tr><tr valign="top"><td>Wrapper:</td><td>None.</td></tr><tr valign="top"><td>Parameters:</td><td>M = 10000.  G = 500.</td></tr><tr valign="top"><td>Success predicate:</td><td>A program scores 211 hits.</td></tr></tbody></table> <strong class='bbc'>Terminals</strong>: The terminal set chosen for the problem was right, left, and forward. Each terminal was a macro that would cause the snake to take the corresponding action during a time step as follows:<br />
<br />
 <em class='bbc'>Right:</em> the snake would change its current direction, making a move to the right<br />
<br />
 <em class='bbc'>Left:</em> the snake would change its current direction, making a move to the left<br />
<br />
 <em class='bbc'>Forward:</em> the snake would maintain its current direction, and move forward. This is the same as a no-op, as the snake must make a move during each time step.<br />
<br />
 These three terminals represent the minimal terminal set with which the snake can effectively navigate its surroundings. While some problems consisting of navigation in a two-dimensional grid can be successfully navigated by way of only one direction changing terminal, that is impractical for the snake game because the facts that the game board is enclosed and that the snake has an extended body that is impassible necessitate the ability for the snake to move in either direction in order to avoid death. More advance terminals, such as moving the snake along the shortest path to the food, were not implemented. Rather, the function set was constructed in such a manner that the GP could evolve the necessary capabilities to achieve the maximum score.<br />
<br />
 <strong class='bbc'>Functions</strong>: Initially the snake was given very limited functionality. One function gave it information about the location of the food, three other functions gave it information about any immediately accessible danger, and progn2 was provided as connective "glue" to allow a function tree to make multiple moves in a single pass. All functions were implemented as macros of arity two, and therefore would only execute one of their arguments depending on the current state of the game, except for progn2, which would execute both of its arguments. Even though no exp<b></b>ressi&#111;ns evolved from this initial function and terminal set were able to achieve the optimum score of 211 pieces of food, this set served as a baseline by which to evaluate progress and determine enhancements the would lead to the eventual optimal solution. Following is a description of the initial function set:<br />
<br />
 <em class='bbc'>ifFoodAhead:</em> If there is food in line with the snake’s current direction, this function will execute its first argument, otherwise it will execute the second argument. This was the only initial function that gave the snake information beyond its immediate surroundings.<br />
<br />
 <em class='bbc'>ifDangerAhead:</em> If the game square immediately in front of the snake is occupied with either a snake body segment or the wall, this function will execute its first argument, otherwise it will execute its second argument.<br />
<br />
 <em class='bbc'>ifDangerRight:</em> If the game square immediately to the right of the snake is occupied with either a snake body segment or the wall, this function will execute its first argument, otherwise it will execute its second argument.<br />
<br />
 <em class='bbc'>ifDangerLeft:</em> If the game square immediately to the left of the snake is occupied with either a snake body segment or the wall, this function will execute its first argument, otherwise it will execute its second argument.<br />
<br />
 <em class='bbc'>progn2:</em> This is a connectivity function that will first execute its right argument, then its left. It is the only function that allows execution of more than one terminal in a single parse of the function tree. Although this function will always execute both of its arguments, it was necessary to implement it as a macro because of the way that the software used to make GP runs, Dave’s Genetic Programming in C (DGPC), evaluated functions vs. macros. To avoid unnecessary modification of DGPC, implementing progn2 as a macro proved the simplest option.<br />
<br />
 As mentioned previously, no GP runs performed with the initial function set were able to score greater than 123 hits. In order to increase the probability of evolving a function tree capable of achieving the maximum number of hits, the initial function set was enhanced. Functions were added to extend the snake’s capabilities for detecting food and danger, as well functions that were conditional on the snake’s current movement direction. Following is a discussion of the additional functions that, along with the initial function set, make up the final function set.<br />
<br />
 Additional Functions, all of arity 2:<br />
<br />
 <em class='bbc'>ifDangerTwoAhead:</em> If the game square two spaces immediately in front of the snake is occupied by either the wall or a segment of the snake’s body, this function will execute the first parameter, otherwise it will execute the second.<br />
<br />
 <em class='bbc'>ifFoodUp:</em> If the current piece of food on the board is closer to the top of the game board than the snake’s head, then the first parameter of this function will be executed, otherwise the second parameter will be executed.<br />
<br />
 <em class='bbc'>ifFoodRight:</em> If the current piece of food on the board is further to the right of the game board than the snake’s head, then the first parameter of this function will be executed, otherwise the second parameter will be executed.<br />
<br />
 <em class='bbc'>ifMovingRight:</em> If the snake is moving right, then the first parameter of this function will be executed, otherwise the second parameter will be executed.<br />
<br />
 <em class='bbc'>ifMovingLeft:</em> If the snake is moving left, then the first parameter of this function will be executed, otherwise the second parameter will be executed.<br />
<br />
 <em class='bbc'>ifMovingUp:</em> If the snake is moving upward, then the first parameter of this function will be executed, otherwise the second parameter will be executed.<br />
<br />
 <em class='bbc'>ifMovingDown:</em> If the snake is moving downward, then the first parameter of this function will be executed, otherwise the second parameter will be executed.<br />
<br />
 There are two characteristics of the final function set that should be given special attention. First, note that the "ifFoodUp" and "ifFoodRight" functions are direction independent, meaning that the direction in which the snake is moving has no impact on the function’s behavior. This is in contrast to the initial set of functions, such as "ifDangerAhead", in which the direction that the snake was traveling would have an impact on the return value of the function. The reason for the difference is to maintain simplicity in the function set. The snake can potentially be surrounded by danger, but there will only be one piece of food on the board at any one time. If the "ifDanger*" functions were direction-independent, then two significant complexities would be added to the problem.<br />
 <ul class='bbcol decimal'><li>An additional function would be required, as there would need to be one for all cardinal directions in order to account for all possible surrounding dangers. An added downfall of this complexity is that one of the "ifDanger*" functions will be virtually meaningless depending on the direction of snake’s travel, since the snake’s neck segment adjacent to the snake’s head is always an adjacent danger, although not one of any consequence to the snake, since it is unable to move back on itself.</li><li>Anytime an "ifDanger*" function was used, it would need the aid of a helper function, such as the new "ifMoving*" functions in order to make intelligent moves based on an assessment of the danger.</li></ul> Taking the second complexity into account, the reader may now note that the same disadvantage is true of the two new functions, "ifFoodUp" and "ifFoodRight." Indeed this is true, but an important difference between the role of food and the role of danger in the game makes for a worthwhile tradeoff. The difference is that there will only be one piece of food on the board at any time. This allows the new "ifFood*" functions to serve as two functions each. To clarify, consider the ifFoodUp function. When not true, it is indicating that the food is either down, or on the same horizontal plane as the snake’s head. Now consider a hypothetical "ifDangerUp" function. If this function were not true, it would tell nothing about whether or not danger is down, because it can be anywhere simultaneously. Likewise is would not even tell whether existing danger that was "up" posed a immediate threat to the snake, as the further information of the snake’s current moving direction would need to be known, as discussed earlier. For the second special characteristic of the new functions, consider the new "ifMoving*" functions. These functions can be used as helper functions with the two new "ifFood*" functions to create beneficial schemata.<br />
<br />
 As an example of a beneficial schemata, consider "ifFoodUp(ifMovingRight(left, ifMovingUp(fwd, right))))", which will orient the snake to pursue food that is upward. As will be seen in the results section, not only does the GP learn how to use these functions in conjunction with the two new "ifFood*" functions, but they also prove useful in helping the snake discover patterns that greatly extend its life. Discussion of other schemata is given below in the description of schemata, and specific examples are given in the "Results" section.<br />
<br />
 <strong class='bbc'>Fitness Cases</strong>: For initial runs of the problem, only a single fitness case was used to determine the fitness for each individual. Because the food placement is random both during a single run, and from one run to another, occasionally individuals would score a number of hits because of fortuitous placement of the food, and not as much on the merit of their function tree.<br />
<br />
 To better ensure that the most successful individuals achieved high fitness measures primarily on the basis of their function tree, new GP runs were often made featuring a "primed" population in which the fitness was measured as the average of four runs of an individual. The procedure for this is as follows: once a run had completed without obtaining a solution, or if a run had stalled on a single individual for a large number (100 or more) of generations, a new run was begun with this final individual as one of the initial individuals. For this new run, however, the fitness was taken as the average fitness of an individual over four runs instead of merely a single run. The averaging of the fitness over four runs helped eliminate the possibility of an individual having a high fitness due simply to lucky placement of the food. Using this averaging method to determine fitness was only used in primed populations because it increased the time of a GP run fourfold. Furthermore, it was common for the generations that timed out to feature an individual who had scored a high fitness as a result of a lucky run. By beginning a new run with this individual in the initial population, it not only assured a more realistic fitness measure, but it introduced an entirely new mix of randomly generated schemata that could potentially benefit the stalled individual. Details of results produced by primed runs are given in the results section.<br />
<br />
 <strong class='bbc'>Fitness Measure</strong>: The fitness measure used is the maximum possible pieces of food eaten, 211, minus the actual number of pieces of food eaten. Furthermore, if the snake was unsuccessful at eating any food the fitness would be penalized by the number of board squares that it was from the food. This additional criterion was added to favor individuals who moved toward the food in early generations of snakes who were unable eat any food.<br />
<br />
 <strong class='bbc'>Parameters</strong>: Population was set to 10000. The maximum number of generations was set to 500. The size of a function tree was limited to 150 points. These parameters were chosen mainly based on available computer resources, covered in computer equipment and run-time explanation below.<br />
<br />
 <strong class='bbc'>Designating a result and criterion for terminating a run</strong>: The best of generation individual will be the one that is able to eat the most pieces of food. A run will end when one of three termination criteria are met:<br />
 <ul class='bbcol decimal'><li>The snake runs into a section of the game board occupied by a wall</li><li>The snake runs into a section of the game board occupied by a segment of the snake’s body</li><li>The number of moves made by the snake exceeds a set limit. This limit was set to 300, slightly larger than the size of the game board. This will prevent a snake from wandering aimlessly around a small portion of the board.</li></ul> The reader may note that there is no termination criterion for the completely successful snake. That is because upon eating the final piece of food, the snake’s tail will grow onto its head, causing it to satisfy termination criteria 2 above. Hence even the optimal solution will end in death for the snake.<br />
<br />
 <strong class='bbc'>Crossover, mutation rates</strong>: Crossover of nodes was the primary genetic operator employed during the GP runs. The crossover fraction for leaves was set to .10; the crossover fraction for a node was set to .80; the mutation fraction was set to 0. Additionally, primed GP runs were used to improve genetic diversity, as described above in the description of fitness cases.<br />
<br />
 <strong class='bbc'>Computer equipment and run time</strong>: The majority of the computer runs were performed on a 550MHz Intel® Celeron Processor running Microsoft® Windows 98 SE Operating System. The software used was Version 2.0 of Dave’s Genetic Programming In C, and Microsoft® Visual C++ 5.0. In addition, a stand-alone simulation of the snake game was created that was able to read in the function trees produced by DGPC and graphically display a run of a particular function tree. This utility proved invaluable, as it provided a fast, visual method to determine the overall optimization strategy represented by the function tree. The alternative of hand-evaluating each function tree would have proven not only more time consuming, but much less conclusive. A complete run of 500 generations took around 20 hours to complete. Because of the length of time for each run, many runs were farmed out to separate computers, all with approximately equivalent computer power.<br />
<br />
 <strong class='bbc'>Schemata</strong>: Given the initial function set, there were a few highly desirable sub-tree schemata that could be produced. First, considering a minimal sub-tree of 3 points, any sub-tree that would evade impending danger by changing directions is certainly the key to survival of an individual. One such sub-tree is "ifDangerAhead(right, forward)." Secondly, a basic sub-tree that will avoid changing directions into impending danger is solely beneficial to an individual. One example is "ifDangerRight(forward, right)." The reader will note that anytime a change in direction is about to be undertaken, it would be wise to have such a check before making the move. Thirdly, a 3-pointed sub-tree that aims at pursuing the food, and modifying directions if no food is ahead, is required to give the individual more than a random opportunity to eat the food pieces. One such individual is "ifFoodAhead(forward, right)."<br />
<br />
 As explained previously, the "ifFoodAhead" function will return true for a piece of food any number of squares in front of the snake. Therefore, in addition to seeking the food, it would also be desirable for the individual to continually scan for impending danger while the food is being sought. Hence a final example of a desirable schemata is any combination of the above three examples that effectively combines the goals of each. For example, consider the following function tree of 7 points: ifFoodAhead(ifDangerAhead(right, forward), ifDangerRight(left, right)). This schema will cause the snake to pursue food ahead as long as no immediate threat is observed. If however, there is a threat or no food ahead, the sub-tree will cause the individual to change direction avoiding any observed danger, or pursuing a new vector to find food. Specific examples of the emergence of such schemata will be given in the results section.<br />
<br />
 In addition to the potential beneficial schemata, touched on above, there are also "detrimental" schemata. The detrimental schemata would be any function branch whose primary goal is to either seek danger or avoid food. Examples of detrimental schemata are essentially the converse of the previously outlined beneficial schemata, and their further consideration is left to the reader.<br />
<br />
 Certainly all schemata are not strictly beneficial or detrimental, and any such schemata will be called "neutral schemata." Consider, for example, the simple subtree "ifDangerRight(left, forward)." This function will turn left if danger is present to the right, and continue forward otherwise. This schema makes either a left or forward move without having any apparent knowledge of what lies in those directions. This could certainly prove to be detrimental, but the move to the left when danger is right is at least avoiding the danger to the right. Schemata such as this can actually prove beneficial when placed in the context of a complete function tree. An examination of actual schemata produced during the GP runs in question follows in the results section.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Results</strong></span><br />
<br />
As mentioned in the methods section, there were three types of GP runs made in an attempt to evolve a solution to the snake game: runs using the initial function set, the final function set, and primed runs, also using the final function set. The highest number of hits generated by a run using the initial function set was 123. Three separate solutions were generated using the final function set, although none of them were found to consistently generate a solution. The number of hits achieved by each solution depended on the placement of the food. It was not until the method of "priming" a run, described in the methods section, was used that a consistent solution was generated. Of ten primed runs, using various initial seeds, exactly five of them evolved a solution, all of which were consistent solutions over multiple runs. Comparatively, over twenty runs using the full function set were made, and only three of them produced solutions, none consistent.<br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[9a922287c5be49409fbe7d41fcd8edca]' id='ipb-attach-url-3158-0-65308500-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3158" title="Image3.gif - Size: 4.38K, Downloads: 85"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-03321700-1308066311_thumb.gif" id='ipb-attach-img-3158-0-65308500-1330207785' style='width:250;height:187' class='attach' width="250" height="187" alt="Attached Image: Image3.gif" /></a></p><br />
 A summary of the overall results achieved in each type of run is given in figure 3. Each line on the graph is the average of ten runs. Note that the initial and final function sets produce a roughly equivalent maximum number of hits until about generation fifty. At this point the final function set continues to improve while the initial function set levels off. By generation 200, the initial function set has virtually no improvement, while the final function set continues improving past generation 400. Because the final function set is both more complete and larger, new and more successful individuals continue to evolve while individuals produced by the initial function set max out around 100 hits. Another feature to note in figure 3 is the impressive results achieved by the primed runs. All primed runs were begun with an individual from a final function set run who had achieved at least 150 hits. When taken as the average over four runs, however, these individuals are only able to achieve about 50 hits, as shown in the first generation of the primed runs. These individuals jumpstart the population to great success, and by generation 25 the maximum number of hits has more than tripled to around 160. By generation 150 the primed runs level off to about 200 hits. Following is an evaluation of some of the most prominent strategies evolved during the various GP runs. Specific examples of individuals from each type of run are presented and analyzed, and all function trees are reduced for simplicity sake.<br />
<br />
 <strong class='bbc'>Zig-zagger</strong>: One strategy that was prevalent in individuals across multiple runs is what will be referred to as the "zig-zagger." These individuals would trace the board diagonally in a stair-stepper pattern until they either reached a wall or had lined the direction of their movement up with the food. Upon reaching a wall, they would change their direction as if bouncing off of the wall, and continue diagonally tracing the board in a new direction. If they were successful in aligning their movement with the piece of food, they would typically head directly toward the food, perhaps avoiding danger depending on the particular individual. Variations in zig-zaggers occurred between which directions they would head when hitting the wall, how often they would seek the food, and how they would react in enclosed situations, such as corners or heading towards food that was blocked by their body. Obviously the more successful individuals evolved traits that allowed them to avoid danger in close quarters and dodge their body when it blocked progress toward the food. One example of a zig-zagger, who was able to score a maximum of 33 hits in one particular run, is given below:<br />
<br />
<span style='font-family: Courier New'><span style='color: #000080'>(ifFoodAhead&nbsp;(ifDangerLeft&nbsp;(right&nbsp;)(ifDangerRight&nbsp;(<sup class='bbc'>1</sup>forward&nbsp;)(ifDangerAhead&nbsp;(left&nbsp;)(&nbsp;<sup class='bbc'>1</sup>forward&nbsp;))))<br />
&nbsp;&nbsp;&nbsp;(ifDangerAhead&nbsp;(ifDangerLeft&nbsp;(right&nbsp;)(left&nbsp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ifDangerLeft&nbsp;(ifDangerRight&nbsp;(forward&nbsp;)(&nbsp;<sup class='bbc'>2</sup>right&nbsp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(progn2&nbsp;(left&nbsp;)(right&nbsp;)))))</span></span><br />
<br />
Consider initially the rightmost sub-tree of the function tree, which is given on the last line as progn2 (left)(right). This is the branch executed initially and for the majority of this zig-zagger’s run. When executed repeatedly, this sub-tree will cause the snake to move left then right, progressing diagonally across the board. For this example, the sub-tree is executed whenever there is no food ahead of the snake’s line of movement, and there is no danger in front of or to the left of the snake’s head. This continuous zig-zagging motion allows the snake to examine successive rows or columns of the board in search of the food. Because both branches of the progn2 are executed before returning to the beginning of the function tree, however, the snake will only detect the food if the second argument of the progn2, right, leaves the snake’s head in line with the food.<br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[9a922287c5be49409fbe7d41fcd8edca]' id='ipb-attach-url-3159-0-65326300-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3159" title="image4.gif - Size: 4.68K, Downloads: 79"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-89116000-1308066356_thumb.gif" id='ipb-attach-img-3159-0-65326300-1330207785' style='width:250;height:178' class='attach' width="250" height="178" alt="Attached Image: image4.gif" /></a></p><br />
 Once the food is directly in line with the movement of the snake’s head, the left-hand sub-tree, given on the first line above, is executed. As noted with a "1" above, the snake will continue forward if there is no danger to the left, and either there is danger to the right, or there is no danger to the right or ahead. Unfortunately for the snake, if there is no danger to the left, but danger to the right and ahead, this function tree will lead it directly into the danger ahead, noted with the first "1" above. This is exactly what happened to the snake in figure 4, shown one time step before its demise after having eaten 24 pieces of food. This snake, whose head is in (14,5), began moving towards the food in (4,5) after having released from the wall.<br />
<br />
 Finally, note that when the "right" portion of the "progn2" sub-tree causes the snake to be either facing or next to a wall, the sub-trees on the second and third line above will be executed respectively. Further investigation reveals that each of these sub-trees will cause the snake to move away from the wall in a direction that avoids danger, even in corners. In this fashion, the snake appears to "bounce" from the walls and proceed to zig-zag in an alternate direction. Two examples of this are seen at positions (17,1) and (20,5) of figure 4. In both of these cases the snake made the right turn noted with a "2" above in order to avoid the wall.<br />
<br />
 <strong class='bbc'>Wall-slitherer</strong>: The strategy that scored the highest out of all individuals using the initial function and terminal set is what will be referred to as the "wall-slitherer." These individuals would follow along the wall, not simply moving forward, but rather slithering back and forth between the two squares closest to the wall. Once able to align its head with the food, the individual would move away from the wall in a straight line to obtain the food. Than, when the food was eaten, successful wall-slitherers would either double-back along their own body and head for the wall or head in a random direction toward a wall. Variations on wall-slitherers occurred in the direction they would take around the wall and when they would leave the wall to pursue the food. One highly successful wall-slitherer is shown below. This individual scored a maximum of 107 hits in one particular run, and an evaluation of its important characteristics follows:<br />
<br />
<span style='font-family: Courier New'><span style='color: #000080'>(ifFoodAhead&nbsp;(ifDangerAhead&nbsp;(left&nbsp;)(forward&nbsp;))<br />
&nbsp;&nbsp;&nbsp;(<sup class='bbc'>1</sup>ifDangerAhead&nbsp;(ifDangerRight&nbsp;(left&nbsp;)(progn2&nbsp;(right&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ifFoodAhead&nbsp;(ifDangerRight&nbsp;(forward&nbsp;)(right&nbsp;)))(ifDangerRight&nbsp;(forward&nbsp;)(right&nbsp;))))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<sup class='bbc'>2</sup>ifDangerRight&nbsp;(ifDangerLeft&nbsp;(forward&nbsp;)(left&nbsp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<sup class='bbc'>3</sup>ifDangerLeft&nbsp;(right&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<sup class='bbc'>4</sup>progn2&nbsp;(left&nbsp;)(ifFoodAhead&nbsp;(ifDangerLeft&nbsp;(right&nbsp;)(left&nbsp;))(ifDangerRight&nbsp;(left&nbsp;)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;<sup class='bbc'>5</sup>progn2&nbsp;(ifDangerAhead&nbsp;(right&nbsp;)(ifDangerLeft&nbsp;(right&nbsp;)(left&nbsp;)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ifDangerRight&nbsp;(forward&nbsp;)(right&nbsp;))))))))))</span></span><br />
<br />
In evaluating this individual, first consider the root, which consists of the "ifFoodAhead" function. For any case in which there is food ahead, the very simple left sub-tree is executed. This subtree simply checks for danger ahead and attempts to avoid it to the left if present, otherwise the snake will continue along its current movement path towards the food. While this sub-tree proves both simple and effective, the fact is clear that the individual spends the majority of its run without the food immediately ahead, which is handled by the much larger right-hand sub-tree.<br />
<br />
 While it appears much more complicated than the left-hand sub-tree, the fundamental strategy of the right-hand sub-tree is to avoid danger. This strategy is executed impressively by the three different "ifDanger*" functions, noted with 1, 2, and 3. These functions provide the roots for the three sub-trees along the right-hand side of the main function tree. The reader can verify that each of these three sub-trees contains schemata that are highly effective at avoiding any impending danger to the snake. Having already taken precautions to pursue food and avoid danger, the final sub-tree provides the snake with its wall-slithering motion, in which it spends the majority of its time.<br />
<br />
 The final sub-tree, noted with a "4" above, is rooted with a progn2. This indicates that multiple actions will be carried out every time this sub-tree is reached, which proves to be very frequently. Initially the branch will make a move to the left, which is already known to be safe. Following this move, if there is no food ahead and no food to the right, then the second progn2, noted with a "5", is reached, making for a total of three moves to be executed on this single pass of the function tree. This three-move sequence is both common and highly beneficial to the success of this wall-slitherer. In figure 5, note the snake’s body segment at (19,8). At this point in the past, the snake was facing downward and a new parse of the function tree was beginning. As no danger was immediately present, sub-tree 4 was reached and the snake turned left towards the wall. Needing to complete the second argument of the progn2, and with no food ahead or danger to the right, the progn2 at 5 was reached, which caused the snake to turn right twice, leading to the next parse of the function tree. Looking back in history through the illustration, note that the same pattern was carried out at points (19,6), (19,4), (19,2), and numerous other times in the brief potion of the snake’s run demonstrated here. This repeated slithering pattern served to maximize the amount of ground covered by the snake while minimizing the danger that its body would pose to itself. A time step prior to a fatal flaw in the snake’s movement, however, is illustrated.<br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[9a922287c5be49409fbe7d41fcd8edca]' id='ipb-attach-url-3161-0-65344700-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3161" title="image5.gif - Size: 5.04K, Downloads: 46"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-36240900-1308066562_thumb.gif" id='ipb-attach-img-3161-0-65344700-1330207785' style='width:250;height:178' class='attach' width="250" height="178" alt="Attached Image: image5.gif" /></a></p><br />
 As the food is in front of the snake’s head, the simple sub-tree on the left is entered. Since there is danger ahead of the snake, it will simply turn left. As shown in the illustration, this turn will lead to the snake’s death, as it hits it’s own body after having eaten 61 pieces of food. While it may seem surprising that this flaw in the left-hand function tree was not encountered sooner, the snake survives by keeping its body along the walls as much as possible. In the illustration, it is clear that the snake left the wall 57 time steps earlier in order to pursue a piece of food across the board. Once the food was eaten, the snake resumed its slither pattern clockwise around the edge of the board. Unfortunately, its body had grown so long that by the time its head was in line with the food at position (19,9) its body was still blocking its path to the food. The snakes evasion tactic of going to the left when danger is encountered with the food ahead had saved in previous similar situations because once a single successful left was made, the snake was no longer in line with the food and it would continue any necessary evasive maneuvers via the much more robust sub-trees, 1, 2, and 3. In this final, fatal case, however, the combination of the snake’s long body, its previous cross-board pursuit of the food, and the placement of the next piece of food three board squares off of the wall caused the evasive left to lead the snake directly into its own body.<br />
<br />
 <strong class='bbc'>Circler</strong>: After the function set was enhanced to include the further food-sensing capabilities of "ifFoodUp" and "ifFoodRight" as well as the four "ifMoving*" functions, a new strategy of behavior that evolved is what will be referred to as the "circler." These individuals would follow along the outside of the wall in a circular pattern and only leave the wall to get the food. Once they reached the food they would continue forward until they reached the wall, then they’d start to circle again. Typically they would only attempt to eat the food while moving in one particular direction. While similar to the wall-slitherer, they differ in two key ways. The first is that the circler will always remain directly next to the wall and not move back and forth like the wall-slitherer. The second is that the circler will typically only leave the wall while headed in one direction. Both of these differences are a direct result of the new functions. Before further discussion, consider the following circler, who scored a maximum of 80 hits over a single run:<br />
<br />
<span style='font-family: Courier New'><span style='color: #000080'>(ifDangerAhead&nbsp;(ifDangerTwoAhead&nbsp;(ifDangerLeft&nbsp;(right&nbsp;)(left&nbsp;))<br />
&nbsp;&nbsp;&nbsp;(ifFoodUp&nbsp;(ifDangerLeft&nbsp;(right&nbsp;)(<sup class='bbc'>2</sup>left&nbsp;))(forward&nbsp;)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ifMovingUp&nbsp;(ifDangerRight&nbsp;(ifFoodUp&nbsp;(forward&nbsp;)(<sup class='bbc'>3</sup>left&nbsp;))(right&nbsp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<sup class='bbc'>1</sup>forward&nbsp;)))</span></span><br />
<br />
First note the leftmost branch of the function tree, in which the snake will primarily avoid danger to both the front and the left. Certainly the left-hand sub-tree, though simple, proves highly effective at achieving the snake’s primary goal of avoiding danger. Secondly, take note of the right-hand sub-tree, which is parsed whenever danger is not immediately ahead of the snake. If the snake is not moving upwards, it simply continues forward, which is already known to be a safe move. This proves to be the move that snake most commonly makes. If, however, the snake is moving upwards, and there is danger to the right, then it will turn left as soon as the food in no longer above it. The primary moves of this snake, then, are to continue forward around the outside of the board until either there is danger ahead and it turns left, or the snake is moving upwards and there is food to left, when it turns left. Note that these moves are marked 1, 2, 3 respectively in the function tree above. Hence when seen in action the snake will make a counterclockwise circular motion around the outside of the board with the top of the circle determined by the current piece of food.<br />
<br />
 <strong class='bbc'>Pattern Following Solution</strong>: As a final example of an evolved strategy, an individual that was able to score the maximum number of hits, 211, will be considered. All individuals who were able to score the maximum number of hits demonstrated some pattern similar to that shown in figure 2. All of these individuals took little to no consideration of where the food was on the board, but rather followed a set pattern that would cover the entire board, eventually causing them to eat the food. Furthermore, the pattern they followed would be continuous, meaning that their head would eventually reach its original starting position, allowing the pattern to continue indefinitely. One such pattern follower, produced in generation 27 of a "primed" run, is given below:<br />
<br />
<span style='font-family: Courier New'><span style='color: #000080'>(ifDangerRight&nbsp;(ifDangerAhead&nbsp;(ifDangerTwoAhead&nbsp;(<sup class='bbc'>8</sup>left&nbsp;)(forward&nbsp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ifMovingRight&nbsp;(<sup class='bbc'>6</sup>left&nbsp;)(&nbsp;<sup class='bbc'>4,7</sup>forward&nbsp;)))<br />
&nbsp;&nbsp;&nbsp;(ifDangerAhead&nbsp;(ifDangerLeft&nbsp;(ifFoodUp&nbsp;(right&nbsp;)(right&nbsp;))(ifDangerTwoAhead&nbsp;(left&nbsp;)(forward&nbsp;)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ifMovingUp&nbsp;(ifDangerTwoAhead&nbsp;(ifFoodAhead&nbsp;(ifMovingRight&nbsp;(<sup class='bbc'>3</sup>right&nbsp;)(&nbsp;<sup class='bbc'>9</sup>forward&nbsp;))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ifMovingDown&nbsp;(left&nbsp;)(&nbsp;<sup class='bbc'>2</sup>right&nbsp;)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(<sup class='bbc'>1</sup>progn2&nbsp;(forward&nbsp;)(forward&nbsp;)))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ifMovingRight&nbsp;(right&nbsp;)(forward&nbsp;)))))</span></span><br />
<br />
This individual followed a pattern exactly the same as that shown in figure 2. There were only a few minor deviations from the pattern that would occur during very infrequent states of the game board. Before considering any such deviations an examination of the major pattern following steps will be made.<br />
<br />
 The overall pattern followed by the individual above is as follows, with the movement steps noted by superscripts on the individual. To simplify the analysis consider that the snake has already eaten enough food to be as long as the board is high, 11 segments, and that the snake is currently moving upward with its head at position (2,10) of the board:<br />
 <ul class='bbcol decimal'><li>While moving upward, if there is not danger two ahead, move forward twice.</li><li>Once there is danger two ahead, turn right; snake now moving right one row from the top of the board.</li><li>Turn right again, to begin heading downward.</li><li>Continue moving downward until there is danger directly ahead.</li><li>Once there is danger ahead, turn left; snake now moving right at the bottom of the board.</li><li>Turn left again and return to step one until there is danger to the right of the snake.</li><li>Danger right indicated the final right-hand column, so the snake now moves up until danger is one ahead.</li><li>Once there is danger ahead, turn left to follow the top row of the board (4,7) while moving left; repeat this same step to move down the left-hand side of the board, and when the bottom of the board is reached, return to step 5.</li></ul> While it is clear that by repeatedly following this pattern the snake will continually trace the whole board, causing it to eat at least one piece of food on each pass of the board, there is one notable exception from the pattern that is made whenever the food is in the top row of the board and the snake is moving upward toward it. In this rare case, when step 2 of the pattern is reached, rather than turning right, the snake will continue forward to eat the food, as noted with a "9" in the function tree. When this case occurs the snake will resume the pattern to the right following its consumption of the food. If, however, this case occurs too far to the right and the snake’s body is long enough, the snake can trap itself on the right side of the board, causing it to die. This is the only way that the way that the individual shown above will not successfully eat 211 pieces of food.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Conclusion</strong></span><br />
<br />
This paper has presented the development and evaluation of a function set capable of evolving an optimal solution to the snake game. An initial function set was presented and evaluated, but proved unsuccessful at evolving an optimal solution. The initial function set was then expanded upon to create the successful final function set, and consistently optimal solutions were generated using primed GP runs. A comparison was made of the results achieved by each function set, as well as by the primed GP runs. Examples of commonly evolved strategies were presented and evaluated, and a final analysis of a consistently successful optimal solution was given.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Future Work</strong></span><br />
<br />
The work presented in this paper provides innumerable opportunities for further investigation into the evolution of a task prioritization scheme within a dynamically changing, randomly updated environment. Specific to the snake problem, modifications can be made to create completely new and interesting problems, such as a non-rectangular game board, obstacles within the game board, or multiple pieces of food. Multiple snakes could be co-evolved to competitively pursue the food. The function set could be modified to feature enhanced detection capabilities and more advanced navigational options. The techniques used for navigating the snake could be generalized to apply to various other problems of interest. Possibilities include automated navigation of multiple robots through a crowded workspace, an automaton for tracking fleeing police suspects through harsh environments, or a control scheme for an exploratory vehicle seeking a particular goal on a harsh alien planet. The possibilities are only limited by the imagination.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>References</strong></span><br />
<br />
Koza, John R. 1992. Genetic Programming: On the Programming of Computers by Means of Natural Selection. Cambridge, Massachusetts: The MIT Press.]]></description>
		<pubDate>Thu, 10 Aug 2000 00:14:21 +0000</pubDate>
		<guid isPermaLink="false">876f1f9954de0aa402d91bb988d12cd4</guid>
	</item>
	<item>
		<title>Chess Programming Part IV: Basic Search</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/chess-programming-part-iv-basic-search-r1171</link>
		<description><![CDATA[Fourth article in this complicated, code-deprived, dry-as-Metamucil series, and you're still reading? Drop me an email if you are, so that I know I'm writing these for a reason!<br />
<br />
 Anyway, this month's installment focuses on the basics of two-agent search in strategy games: why it is useful, how to do it, and what it implies for the computer's style of play. The techniques I will discuss apply equally well to most two-player games, but by themselves, they are not quite sufficient to play good chess; next month, I will describe advanced techniques which significantly increase playing strength and search efficiency, usually at the same time.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Why Search?</strong></span><br />
<br />
Well, basically, because we are not smart enough to do without it.<br />
<br />
 A really bright program might be able to look at a board position and determine who is ahead, by how much, and what sort of plan should be implemented to drive the advantage to fruition. Unfortunately, there are so many patterns to discern, so many rules and so many exceptions, that even the cleverest programs just aren't very good at this sort of thing. What they <em class='bbc'>are</em> good at, however, is computing fast. Therefore, instead of trying to figure out good moves just by looking at a board, chess programs use their brute force to do it: look at every move, then at every possible countermove by the opponent, etc., until the processor melts down.<br />
<br />
 Deep searches are an easy way to "teach" the machine about relatively complicated tactics. For example, consider the knight fork, a move which places a knight on a square from which it can attack two different pieces (say, a rook and the queen). Finding a way to represent this type of position logically would require some effort, more so if we also had to determine whether the knight was itself protected from capture. However, a plain dumb 3-ply search will "learn" the value of a fork on its own: it will eventually try to move the knight to the forking square, will test all replies to this attack, and then capture one of the undefended pieces, changing the board's material balance. And since a full-width search looks at everything, it will never miss an opportunity: if there is a 5-move combination, however obscure, that leads to checkmate or to a queen capture, the machine <em class='bbc'>will</em> see it if its search is deep enough. Therefore, the deeper the search, the more complicated the "plans" which the machine can stumble upon.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Grandpa MiniMax</strong></span><br />
<br />
The basic idea underlying all two-agent search algorithms is Minimax. It dates back from the Dark Ages; I believe Von Neumann himself first described it over 60 years ago.<br />
<br />
 Minimax can be defined as follows:<br />
 <ul class='bbc'><li>Assume that there is a way to evaluate a board position so that we know whether Player 1 (whom we will call Max) is going to win, whether his opponent (Min) will, or whether the position will lead to a draw. This evaluation takes the form of a number: a positive number indicates that Max is leading, a negative number, that Min is ahead, and a zero, that nobody has acquired an advantage.</li><li>Max's job is to make moves which will increase the board's evaluation (i.e., he will try to maximize the evaluation).</li><li>Min's job is to make moves which decrease the board's evaluation (i.e., he will try to minimize it).</li><li>Assume that both players play flawlessly, i.e., that they never make any mistakes and always make the moves that improve their respective positions the most.</li></ul> How does this work? Well, suppose that there is a simple game which consists of exactly one move for each player, and that each has only two possible choices to make in a given situation. The evaluation function is only run on the final board positions, which result from a combination of moves by Min and Max.<br />
<br />
 <table border="1" cellpadding="4" cellspacing="0"><tbody><tr bgcolor="#666699"><td align="center"><font color="white"><b>Max Move</b></font></td><td align="center"><font color="white"><b>Min Move</b></font></td><td align="center"><font color="white"><b>Evaluation</b></font></td></tr><tr><td align="center">A</td><td align="center">C</td><td align="center">12</td></tr><tr><td align="center">A</td><td align="center">D</td><td align="center">-2</td></tr><tr><td align="center">B</td><td align="center">C</td><td align="center">5</td></tr><tr><td align="center">B</td><td align="center">D</td><td align="center">6</td></tr></tbody></table>Max assumes that Min will always play perfectly. Therefore, he knows that, if he makes move A, his opponent will reply with D, resulting in a final evaluation of -2 (i.e., a win for Min). However, if Max plays B, he is sure to win, because Min's best move still results in a positive final value of 5. So, by the Minimax algorithm, Max will always choose to play B, even though he would score a bigger victory if he played A and Min made a mistake!<br />
<br />
 The trouble with Minimax, which may not be immediately obvious from such a small example, is that there is an exponential number of possible paths which must be examined. This means that effort grows dramatically with:<br />
 <ul class='bbc'><li>The number of possible moves by each player, called the branching factor and noted B.</li><li>The depth of the look-ahead, noted d, and usually described as "N-ply", where N is an integer number and "ply" means one move by one player. For example, the mini-game described above is searched to a depth of 2-ply, one move per player.</li></ul> In Chess, for example, a typical branching factor in the middle game would be about 35 moves; in Othello, around 8. Since Minimax' complexity is O( B^n ), an 8-ply search of a chess position would need to explore about 1.5 million possible paths! That is a LOT of work. Adding a ninth ply would make the tree balloon to about 50 million nodes, and a tenth, to an impossible 1.8 billion!<br />
<br />
 Luckily, there are ways to cut the effort by a wide margin without sacrificing accuracy.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Alphabeta: Making Minimax Feasible (a little)</strong></span><br />
<br />
Suppose that you have already searched Max' move B in the mini-game above. Therefore, you know that, at best, Max' score for the entire game will be 5.<br />
<br />
 Now, suppose that you begin searching move A, and that you start with the path A-D. This path results in a score of -2. For Max, this is terrible: if he plays A, he is sure to finish with, at best, -2, because Min plays perfectly; if A-C results in a score higher than A-D's, Min will play A-D, and if A-C should be even worse (say, -20), Min would take that path instead. Therefore, <em class='bbc'>there is no need to look at A-C</em>, or at any other path resulting from move A: Max must play B, because the search has already proven that A will end up being a worse choice no matter what happens.<br />
<br />
 This is the basic idea being the alphabeta algorithm: once you have a good move, you can quickly eliminate alternatives that lead to disaster. And there are <em class='bbc'>a lot</em> of those! When combined with the transposition table we discussed earlier in the series, and which saves us from examining positions twice if they can be reached by different combinations of moves, alphabeta turns on the Warp drive: in the best case, it will only need to examine roughly twice the square root of the number of nodes searched by pure Minimax, which is about 2,500 instead of 1.5 million in the example above.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Ordering Moves to Optimize Alphabeta</strong></span><br />
<br />
But how can we achieve this best case scenario? Do we even need to?<br />
<br />
 Not really. It turns out that Alphabeta is always very efficient at pruning the search tree, as long as it can quickly find a pretty good move to compare others to. This means that it is important to search a good move first; the best case happens when we always look at the best possible moves before any others. In the worst possible case, however, the moves are searched in increasing order of value, so that each one is always better than anything examined before; in this situation, alphabeta can't prune <em class='bbc'>anything</em> and the search degenerates into pure, wasteful Minimax.<br />
<br />
 Ordering the moves before search is therefore very important. Picking moves at random just won't do; we need a "smarter" way to do the job. Unfortunately, if there was an easy way to know what the best move would turn out to be, there would be no need to search in the first place! So we have to make do with a "best guess".<br />
<br />
 Several techniques have been developed to order the possible moves in as close to an optimal sequence as possible:<br />
 <ul class='bbc'><li>Apply the evaluation function to the positions resulting from the moves, and sort them. Intuitively, this makes sense, and the better the evaluation function, the more effective this method should be. Unfortunately, it doesn't work well at all for chess, because as we will see next month, many positions just can't be evaluated accurately!</li><li>Try to find a move which results in a position already stored in the transposition table; if its value is good enough to cause a cutoff, no search effort needs to be expended.</li><li>Try certain types of moves first. For example, having your queen captured is rarely a smart idea, so checking for captures first may reveal "bonehead" moves rapidly.</li><li>Extend this idea to any move which has recently caused a cutoff at the same level in the search tree. This "killer heuristic" is based on the fact that many moves are inconsequential: if your queen is en prise, it doesn't matter whether you advance your pawn at H2 by one or two squares; the opponent will still take the queen. Therefore, if the move "bishop takes queen" has caused a cutoff during the examination of move H2-H3, it might also cause one during the examination of H2-H4, and should be tried first.</li><li>Extend the killer heuristic into a history table. If, during the course of the game's recent development, moving a piece from G2 to E4 has proven effective, then it is likely that doing so now would still be useful (even if the old piece was a bishop and has been replaced by a queen), because conditions elsewhere on the board probably haven't changed that much. The history heuristic is laughably simple to implement, needing only a pair of 64x64 arrays of integer counters, and yields very interesting results.</li></ul> Having said all that about "reasonable ideas", it turns out that the most effective method is one which goes against every single bit of human intuition: iterative deepening.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Iterative Deepening AlphaBeta</strong></span><br />
<br />
If you are searching a position to depth 6, the ideal move ordering would be the one yielded by a prior search of the same position to the same depth. Since that is obviously impossible, how about using the results of a shallower search, say of depth 5?<br />
<br />
 This is the idea behind iterative deepening: begin by searching all moves arising from the position to depth 2, use the scores to reorder the moves, search again to depth 3, reorder, etc., until you have reached the appropriate depth.<br />
<br />
 This technique flies in the face of common sense: a tremendous amount of effort is duplicated, possibly 8-10 times or more. Or is it?<br />
<br />
 Consider the size of a search tree of depth d with branching factor B. The tree has B nodes at depth 1, B*B at depth 2, B*B*B at depth 3, etc. Therefore, searching to depth (d-1) yields a tree B times smaller than searching to depth d! If B is large (and remember that it is about 35 during the middle game in chess), the overwhelming majority of the effort expended during search is devoted to the very last ply. Duplicating a search to depth (d-1) is a trifling matter: in fact, even if it yielded no advantages whatsoever, iterative deepening would only cost less than 4% extra effort on a typical chess position!<br />
<br />
 However, the advantages are there, and they are enormous: using the results of a shallower search to order the moves prior to a deeper one produces a spectacular increase in the cutoff rate. Therefore, IDAB actually examines <em class='bbc'>far fewer</em> nodes, on average, than a straight AB search to the same depth using any other technique for move ordering! When a transposition table enters the equation, the gain is even more impressive: the extra work performed to duplicate the shallow parts of the search drops to nothing because the results are already stored in the table and need not be computed again.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Computer Playing Style</strong></span><br />
<br />
Iterative deepening alphabeta combined with a transposition table (and a history table to kickstart the effort) allows the computer to search every position relatively deeply and to play a reasonable game of chess. That being said, its Minimax ancestor imposes a very definite playing style on the computer, one which is not exactly the most spectacular in the world.<br />
<br />
 For example, suppose that the machine searches a position to depth 8. While looking at a certain move, it sees that every possible response by the opponent would let it win the game in dazzling manner... Except for a single opaque, difficult, obfuscated and almost maddeningly counter-intuitive sequence, which (if followed to perfection) would allow the opponent to salvage a small chance of eventually winning the game. Against a human player (even a Grandmaster), such a trap might turn the game into one for the history books.<br />
<br />
 However, if the machine then finds a boring move which always forces a draw, it will immediately discard the trap, because it assumes that the opponent would find the perfect counter, no matter how improbable that is, and that the draw is the best it can hope for!<br />
<br />
 As a result, you might say that machines play an overly cautious game, as if every opponent was a potential world champion. Combined with the fact that computers often can't search deep enough to detect the traps which human players devise against them, this allows very skilled humans to "waste time" and confuse the machine into making a blunder which they can exploit. (Human players also study their opponent's styles for weaknesses; if Kasparov had been given access to, say, a hundred games played by Deep Blue before their match, he might have been able to find the flaws in its game and beat it. But we'll never know for sure.)<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Next Month</strong></span><br />
<br />
In Part V, we will discuss the limitations of straight, fixed-depth alphabeta search, and how to improve playing strength using techniques like the null-move heuristic, quiescence search, aspiration search and MTD(f), and the "singular extensions" which made Deep Blue famous. Hold on, we're almost done!<br />
<br />
<em class='bbc'> François Dominic Laramée, August 2000</em>]]></description>
		<pubDate>Sun, 06 Aug 2000 22:25:57 +0000</pubDate>
		<guid isPermaLink="false">3bc31a430954d8326605fc690ed22f4d</guid>
	</item>
	<item>
		<title>Chess Programming Part III: Move Generation</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/chess-programming-part-iii-move-generation-r1126</link>
		<description><![CDATA[Last month, I finished Part II of this series by introducing a data structure which pre-processes and stores most of the work related to chess move generation.  This time, I will return to the topic in more detail, examining the two major move generation strategies and explaining how to choose between them for a given application.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>The Dilemma</strong></span><br />
<br />
No matter how you slice it, chess is a complicated game, especially for a computer.<br />
<br />
 In any given situation, a player may have 30 or more legal moves to choose from, some good, some suicidal.  For trained humans, it is easy to characterize the majority of these moves as foolish or pointless: even beginners learn that they had better come up with a solid plan before leaving their queen in a position where she can be captured, and masters know (more through instinctive pattern matching than by conscious effort) which 1-2 moves are likely to be the strongest in the position.<br />
<br />
 However, coding this information (especially the unconscious type!) into a computer has proven spectacularly difficult, and the strongest programs (except, to some extent, Hans Berliner's Hitech and its siblings) have given up on this approach, instead relying on "brute force": if you can analyze all possible moves fast enough and predict their consequences far enough down the road, it doesn't matter whether or not you start with a clear idea of what you are trying to accomplish, because you'll discover a good move <em class='bbc'>eventually</em>.  Therefore, move generation and search should be made as fast as possible, so as to minimize the loss of effort required by the brute force method.<br />
<br />
 Search will be discussed in Parts IV and V of this series; this month, we will concentrate on move generation.  Historically, three major strategies have been used in this area:<br />
 <ul class='bbc'><li>Selective generation: Examine the board, come up with a small number of "likely" moves and discard everything else.</li><li>Incremental generation: Generate a few moves, hoping that one will prove so good or so bad that search along the current line of play can be terminated before generating the others.</li><li>Complete generation: Generate all moves, hoping that the transposition table (discussed in Part II) will contain relevant information on one of them and that there will be no need to search anything at all.</li></ul> Selective generation (and its associated search technique, called forward pruning) have all but disappeared since the mid 1970's.  As for the other two, they represent two sides of the same coin, trading off effort in move generation vs search.  In games where move generation is easy and/or there are lots of ways to transpose into the same positions (i.e., Othello and GoMoku), complete generation may be most efficient, while in games where move generation rules are complicated, incremental generation will usually work faster.  Both strategies are sound and viable, however.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>The Early Days: Forward Pruning</strong></span><br />
<br />
In 1949 (yes, really), Claude Shannon described two ways to build a chess-playing algorithm:<br />
 <ul class='bbc'><li>Look at all possible moves, and all the possible moves resulting from each, recursively.</li><li>Only examine the "best" moves, as determined from a detailed analysis of a position, and then only the "best" replies to each, recursively.</li></ul> At first, the second alternative seemed more likely to succeed.  After all, this is how human players do it, and it seems logical to assume that looking at only a few moves at each node will be faster than looking at all of them.  Unfortunately, the results disproved the theory: programs using selective search just didn't play very well.  At best, they achieved low to mid-level club player ratings, often committing humiliating blunders at the worst possible time.  Beating a world champion (or even playing reasonably well on a consistent basis) was beyond their reach.<br />
<br />
 The problem is that, for a "best move generator" to be any good, it has to be almost perfect.  Suppose that a program is equipped with a function that looks for the 5 best moves in a position, and that the objective best move is among those 5 at least 95% of the time.  (That, by the way, is a <em class='bbc'>big</em> assumption.)  This means that the probability that the generator's list will always contain the best choice at all times, during a 40-move game, is <em class='bbc'>less than 13%</em>.  Even a god-like generator with 99% accuracy will blunder at least once in about a third of its games, while a more reasonable 90%-accurate function will play an entire game without messing up less than 1.5% of the time!<br />
<br />
 In the mid 1970's, the legendary Northwestern team of Slate and Atkin decided to do away with the complicated best-move generator; it turned out that the time they saved in avoiding costly analysis during move generation was enough to cover the added expense of a full-width search (i.e., examining all possible moves).  To all intents and purposes, this discovery buried forward pruning for good.<br />
<br />
 <strong class='bbc'>Botvinnik's work</strong><br />
An extreme example of a forward pruning algorithm was developed in the Soviet Union, in the 1970's and early 1980's, under the tutelage of former World chess champion Mikhail Botvinnik.  Botvinnik was convinced that the only way for a computer to ever play grandmaster-level chess was to play like a grandmaster, i.e., examine only a few moves, but in great depth and detail.  His program seeked to identify and implement the sort of high-level plans and patterns which a world-class player might come up with during a game.  While it led to some fascinating books, revealing insights into the master's mind which only Botvinnik could provide, this work unfortunately did not reach its lofty goals.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Generating All Moves Up-Front</strong></span><br />
<br />
Once forward pruning is eliminated from consideration, the most straightforward way to implement full-width searching consists of:<br />
 <ul class='bbc'><li>Finding all of the legal moves available in a position.</li><li>Ordering them in some way, hopefully speeding up search by picking an advantageous order.</li><li>Searching them all one at a time, until all moves have been examined or a cutoff occurs.</li></ul> Early programs, for example Sargon, did this by scanning the board one square at a time, looking for pieces of the moving side, and computing possible move destinations on the fly.  Memory being at a premium, the expenditure of CPU time required to re-compute these moves every time was a necessary evil.<br />
<br />
 These days, a pre-processed data structure like the one I described last month can avoid a considerable amount of computation and code complexity, at the cost of a few dozens of Kbytes.  When this super-fast move generation is combined with transposition tables, an added bonus may fall into the programmer's lap: if even one of the moves has already been searched before, and if its evaluation (as retrieved from the table) is such that it triggers a cutoff, there will be no need to search any of the moves at all!  Obviously, the larger the transposition table, and the higher the probability of a transposition given the rules of the game, the bigger the average payoff.<br />
<br />
 Not only is this technique conceptually simple, it is also the most "universal": while there are easy ways to segregate chess moves into different categories (i.e., captures and non-captures), other games like Othello do not provide such convenient tools to work with.  Therefore, if you intend your program to play more than one game, you should probably pick this technique instead of the one described in the next section.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>One Move At A Time</strong></span><br />
<br />
Sophisticated chess programs since at least CHESS 4.5 have adopted the opposite strategy: generate a few moves at a time, search them, and if a cutoff can be caused, there will be no need to generate the rest of the moves.<br />
<br />
 A combination of factors has made this technique popular:<br />
 <ul class='bbc'><li>Search does not require much memory.  Programs of the 1970's had to make do with small transposition tables and could ill afford  pre-processed move generation data structures, limiting the usefulness of the complete generation scheme described above.</li><li>Move generation is more complicated in chess than in most other games, with castling, en passant pawn captures, and different rules for each piece type to contend with.</li><li>Very often, a refutation (i.e., a move that will cause a cutoff) is a capture.  For example, if Player A leaves a queen "en prise", the opponent will quickly grab it and wreck A's game.  Since there are usually few possible captures in a position, and since generating captures separately is relatively easy, computing captures is often enough to trigger a cutoff at little expense.</li><li>Captures are usually one of the few (if not the only) type of move examined during quiescence search (which will be discussed in a later article), so generating them separately is doubly useful.</li></ul> Therefore, many programs will generate captures first, often starting with those of highly valuable pieces, and look for a quick cutoff.  A number of techniques have been developed to speed up piece-meal move generation, most of them involving bitboards:<br />
 <ul class='bbc'><li>CHESS 4.5 maintains two sets of 64 bitboards, with one bitboard per square on the board.  One contains the squares attacked by the piece, if any, located on that square; the other is the transpose, containing all squares occupied by pieces attacking that square.  Therefore, if the program is looking for moves that would capture Black's queen, it looks for its position in the basic bitboard database, uses these new data structures to identify the pieces which attack the queen's position, and only generates moves for these pieces.</li><li>Maintaining these "attack bitboards" after each move requires some rather involved technical wizardry, but a tool called a rotated bitboard can accelerate the work significantly.  The best discussion of rotated bitboards I have seen was written by James F. Swafford, and can be found on the web at <a href='http://sr5.xoom.com/_XMCM/jswaff/chessprg/rotated.htm' class='bbc_url' title='External link' rel='nofollow external'>http://sr5.xoom.com/...prg/rotated.htm</a></li></ul> <br />
<span style='font-size: 18px;'><strong class='bbc'>Ordering Moves To Speed Up Search</strong></span><br />
<br />
As we will see next time, search efficiency depends on the order in which moves are searched.  The gains and losses related to good or poor move ordering are not trivial: a good ordering, defined as one which will cause a large number of cutoffs, will result in a search tree about the <em class='bbc'>square root</em> of the size of the tree associated with the worst possible ordering!<br />
<br />
 Unfortunately, it turns out that the best possible ordering is simply defined by trying the best move first.  And of course, if you knew which moves are best, you wouldn't be searching in the first place.  Still, there are ways to "guess" which moves are more likely to be good than others.  For example, you might start with captures, pawn promotions (which dramatically change material balance on the board), or checks (which often allow few legal responses); follow with moves which caused recent cutoffs at the same depth in the tree (so-called "killer moves"), and then look at the rest.  This is the justification for iterative deepening alphabeta, which we will discuss in detail next month, as well as the history table we talked about last time.  Note that these techniques do not constitute forward pruning: all moves will be examined eventually; those which appear bad are only delayed, not eliminated from consideration.<br />
<br />
 A final note: in chess, some moves may be illegal because they leave the King in check.  However, such an occurrence is quite rare, and it turns out that validating moves during generation would cost a tremendous amount of effort.  It is more efficient to delay the check until the move is actually searched: for example, if capturing the King would be a valid reply to Move X, then Move X is illegal and search should be terminated.  Of course, if search is cutoff before the move has to be examined, validation never has to take place.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>My Choice</strong></span><br />
<br />
For my chess program, I have chosen to generate all moves at the same time.  These are only some of the reasons why:<br />
 <ul class='bbc'><li>I intend to use the program as a basis for several other games, most of which have no direct counterparts to chess captures.</li><li>I have plenty of memory to play with.</li><li>The code required to implement this technique is simpler to write and to understand; you will thank me when you see it.</li><li>There are several freeware programs that implement piece-meal move generation; the curious reader should look at Crafty, for example, as well as James Swafford's Galahad.</li></ul> While overall performance may be slightly less stellar than otherwise, my program (written in Java, no less) wouldn't exactly provide a challenge to Deep Blue even in the best case, so I won't feel too bad!<br />
<br />
<br />
<span style='font-size: 18px;'> <strong class='bbc'>Next Month</strong></span><br />
<br />
Now, we are ready to delve into the brains of a chess-playing program, with search techniques.  This is such a large topic that it will require two articles.  We will begin with the basic search algorithms common to all games, before continuing with new developments and chess-specific optimizations in the next installment.<br />
 <br />
<br />
<em class='bbc'> François Dominic Laramée, July 2000</em>]]></description>
		<pubDate>Mon, 17 Jul 2000 00:44:13 +0000</pubDate>
		<guid isPermaLink="false">0b74c9847e45c3be47e0d1a8f92bcab8</guid>
	</item>
	<item>
		<title>Motion Planning Using Potential Fields</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/motion-planning-using-potential-fields-r1125</link>
		<description><![CDATA[<span style='font-size: 18px;'><strong class='bbc'>Introduction</strong></span><br />
<br />
First of all, I'm no authority on pathfinding or motion planning. There just seems to be a lot of interest in pathfinding algorithms on the artificial intelligence message board. Last year I did a big project on motion planning for a university course, but since almost nobody on the net understands Dutch, I thought it might be best to translate it and let a much broader public get acquainted with the general concepts of motion planning. In this article I'll shed some light on several techniques using potential fields. We'll focus on the theoretical part of the algorithms and now and then I'll throw in some screenshots from a demo-application I made for the project.<br />
<br />
 Should you have more questions or ideas on the subject, my name is <a href='mailto:StrategicAlliance@softline.be' title='E-mail Link' class='bbc_email'>Stefan Baert</a>, I live in Belgium and on the net you'll mostly find me as 'StrategicAlliance'.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>What is a potential field anyway?</strong></span><br />
<br />
Before we start we have to agree on some definitions. We'll be talking about a pixel-sized 'unit' that can freely maneuver in all 8 directions at a speed of one pixel per turn in an environment. This environment is a 2D-map that has been divided in squares, sized one pixel each. In this example we'll take a 100*100 environment and call it a 'grid'. The borders are walls that can not be penetrated and there are several 'objects' on the map which have to be avoided. In theory, these objects can have any form, but we'll focus on differently sized rectangles.<br />
<br />
 Now, what we still have to do is define a potential field. In essence, you could think of it as a big matrix. Every pixel in the 'grid' we mentioned above is represented in the matrix by a number, telling us something about the state of that pixel under the current circumstances. Since our ultimate goal is to find a path from our starting location to our destination, it's logical to assume that we're going to manipulate and use these numbers as the decisive factor to move in the 'grid'.<br />
<br />
 In the examples below we'll always try to make the 'potential' of our destination as low as possible, while making the starting location as high as possible. We can then, symbolically, glide down the numbers, moving from pixel to pixel in the grid, only accessing pixels in the grid that have a lower potential than the one our unit stands in at that moment. To avoid bumping into obstacles we'll give them a very high potential value (higher than the highest accessible pixel in the grid) so our unit will never be tempted to enter such an object.<br />
<br />
 In the included screenshot you see a potential field indicated with colors. In this case a lower potential means a darker green. The unit is the blue pixel in the top left corner. Our goal is the red pixel in the lower right corner. Obstacles are shown in white.<br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[451b909d33aa4b3ab3857d4fa935832d]' id='ipb-attach-url-3135-0-74871200-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3135" title="MP_shot1.gif - Size: 10.14K, Downloads: 56"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-80342700-1307992519_thumb.gif" id='ipb-attach-img-3135-0-74871200-1330207785' style='width:200;height:200' class='attach' width="200" height="200" alt="Attached Image: MP_shot1.gif" /></a> </p><br />
 <strong class='bbc'><br />
<span style='font-size: 18px;'>Technique 1 : Forward... march!</span></strong><br />
<br />
We'll now look at a few techniques. Each one will be slightly more complicated than the previous one, solving the problems from the previous technique, but unfortunately creating different ones at the same time.<br />
<br />
 We start easy. We calculate the distance in each pixel point to the destination and give this distance as 'potential' value to that pixel. Please note that in this case you don't have to care about the obstacles (just give them a very high value). The distance from the destination to a pixel can be measured in a straight line. Once this is done we apply this algorithm : "Check all the neighboring pixels of the current pixel and select the one with the lowest potential value. Move to that pixel and continue to do this until you reach your goal or get stuck."<br />
<br />
 It can hardly be easier and this algorithm works quite well if you have few objects in the grid, but most of the time the unit will get stuck behind an object and have no way to get back on the right track.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Technique 2 : Filling local minima</strong></span><br />
<br />
As we saw in the first technique it is possible to get stuck. This happens when the unit enters a local minimum. In the potential field this is represented by a pixel that has neighbors which are either objects or are accessible but have a higher value, yet they are not our destination. If you have some experience with theoretical algorithms you may have noticed that we performed a depth-first search in the grid.<br />
<br />
 We'll improve our algorithm by using a best-first search. We'll do this by building a tree with the pixels in the grid. Our root in the tree is the starting location. This root has the 8 directions in which our unit can travel as children. We'll take the child with the lowest value and evaluate all the directions we can travel from here, but not the ones that are already in the tree. We then evaluate all the leaves in the tree and repeat the process for the leave with the lowest value. We continue to do this until we either find our destination or until we have evaluated all leaves and cannot find another pixel to move to (which will happen if the destination is simply unreachable from our starting location). If we are successful the path is defined by traversing the tree from the root to the leave containing our destination.<br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[451b909d33aa4b3ab3857d4fa935832d]' id='ipb-attach-url-3136-0-74886000-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3136" title="MP_shot2.gif - Size: 11.28K, Downloads: 63"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-81973000-1307992561_thumb.gif" id='ipb-attach-img-3136-0-74886000-1330207785' style='width:200;height:200' class='attach' width="200" height="200" alt="Attached Image: MP_shot2.gif" /></a></p><br />
 If you do a graphical representation of building the tree, you can see that local minima are 'filled' until the 'bucket runs over' and we can continue a straight line to our goal. In the picture, the members of the tree are blue, except for the leaves which are yellow. Obstacles are represented in white.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Technique 3 : It is better to prevent...</strong></span><br />
<br />
We may have found a way to get out of local minima in our previous solution, but it would be better if we could just find a way to have no local minima at all. To accomplish this we need to change the way in which we build our potential field.<br />
<br />
 Instead of directly calculating the distance between a pixel and the destination, we'll give our destination zero as value and then apply this algorithm : Every direct (horizontal and vertical but not diagonal) neighbor of the destination gets value 1, then their direct neighbors get 2, and so on...<br />
<br />
 We can then start of where our unit is and glide down the numbers to our goal. Since only our destination has a zero value and every other pixel always has a neighbor with a lower value we'll be successful when a path exists. This method is also known as a wavefront-expansion.<br />
<br />
<p class='bbc_center'> <a class='resized_img' rel='lightbox[451b909d33aa4b3ab3857d4fa935832d]' id='ipb-attach-url-3137-0-74897200-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3137" title="MP_shot3.gif - Size: 11.09K, Downloads: 53"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-13899600-1307992594_thumb.gif" id='ipb-attach-img-3137-0-74897200-1330207785' style='width:200;height:200' class='attach' width="200" height="200" alt="Attached Image: MP_shot3.gif" /></a></p><br />
 If you look at the picture you'll notice that local minima now get a higher value (indicated by a brighter yellow) because it's a longer way around an object to get there than in a straight line. The path we follow is indicated by the blue line moving east and then south.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Technique 4 : Get away from the edges</strong></span><br />
<br />
Since we began our exploration of the potential field, we've learned to get out of minima and even to ban them completely. But you'll have noticed in the last screenshot that we were moving dangerously close to the edge of objects and walls. In an environment where we might only know an approximate location of objects it would be best to stay as far away from them as possible to avoid collisions.<br />
<br />
 For this we need to enhance our algorithm from the previous technique. Instead of initiating one wavefront in the destination, we will now start a wavefront in every pixel that is on the edge of an object. Each of these 'edge-pixels' gets a unique ID and gives this ID to all his direct neighbors. When two ID's that are sufficiently different collide we've found the middle between two close objects. The result will be a kind of Voronoi diagram between the objects which we can use as roadmap to navigate between the objects. All we then have to do is give the pixels in the grid that do not belong to this roadmap, a value so that our unit will get on the roadmap as soon as possible. For this we can use one of the techniques above.<br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[451b909d33aa4b3ab3857d4fa935832d]' id='ipb-attach-url-3138-0-74907800-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=3138" title="MP_shot4.gif - Size: 14.87K, Downloads: 58"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-77480600-1307992631_thumb.gif" id='ipb-attach-img-3138-0-74907800-1330207785' style='width:200;height:200' class='attach' width="200" height="200" alt="Attached Image: MP_shot4.gif" /></a></p><br />
 The picture shows wavefronts coming from the edges of the objects and a purple roadmap exactly in the middle between several objects.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Conclusion</strong></span><br />
<br />
This concludes our voyage using potential fields. The techniques described above are an interesting alternative for the A* algorithm that seems to be very popular these days. Though potential fields require some serious calculations to be applied their characteristic of defining a whole grid in numbers can be an asset if you need quickly changing destination goals, because all you need to do is increase or decrease the numbers in a certain region to make it more attractive (or not) for the unit to follow that path.]]></description>
		<pubDate>Sat, 15 Jul 2000 13:06:24 +0000</pubDate>
		<guid isPermaLink="false">cbca7635077d4074f8d30094a3176972</guid>
	</item>
	<item>
		<title>Chess Programming Part II: Data Structures</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/chess-programming-part-ii-data-structures-r1046</link>
		<description><![CDATA[Last month, I presented the major building blocks required to write a program to play chess, or any other two-player game of perfect information.  Today, I will discuss in a bit more detail the most fundamental of these building blocks: the internal representation of the game board.<br />
<br />
 You may be surprised to notice that, for all intents and purposes, the state of the art in this area has not changed in thirty years.  This is due to a combination of ingenuity (i.e., smart people made smart choices very early in the field's history) and necessity (i.e., good data structures were a pre-requisite to everything else, and without these effective techniques, not much would have been achieved.)<br />
<br />
 While we're at it, I will also present three support data structures which, although not absolutely required to make the computer <em class='bbc'>play</em>, are invaluable if you want it to play <em class='bbc'>well</em>.  Of these, two (one of which consumes ungodly amounts of memory) are designed to accelerate search through the game tree, while the third is used to speed up move generation.<br />
<br />
 Before we go any further, a word to the wise: in chess as in any other game, the simplest data structure that will get the job done is usually the one you should use.  While chess programmers have developed numerous clever data representation tricks to make their programs go faster, very simple stuff is quite sufficient in many other games.  If you are a novice working on a game for which there is limited literature, start with something easy, encapsulate it well, and you can experiment with more advanced representations once your program works.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Basic Board Representations</strong></span><br />
<br />
Back in the 1970's, personal computer memory was at a premium (that's an understatement if there ever was one!), so the most compact the board representations, the better.  There is a lot to be said for the most self-evident scheme: a 64-byte array, where each byte represents a single square on the board and contains an integer constant representing the piece located in that square.  (Any chess board data structure also needs a few bytes of storage to track down <em class='bbc'>en passant</em> pawn capture opportunities and castling privileges, but we'll ignore that for now, since this is usually implemented separately, and pretty much always the same way.)<br />
<br />
 A few refinements on this technique soon became popular:<br />
 <ul class='bbc'><li>The original SARGON extended the 64-byte array by surrounding it with two layers of "bogus squares" containing sentinel values marking the squares as illegal.  This trick accelerated move generation: for example, a bishop would generate moves by sliding one square at a time until it reached an illegal square, then stop.  No need for complicated <em class='bbc'>a priori</em> computations to make sure that a move would not take a piece out of the memory area associated with the board.  The second layer of fake squares is required by knight moves: for example, a knight on a corner square might try to jump out of bounds by two columns, so a single protection layer would be no protection at all!</li><li>MYCHESS reversed the process and represented the board in only 32 bytes, each of which was associated with a single piece (i.e., the white king, the black King's Knight's pawn, etc.) and contained the number of the square where that piece was located, or a sentinel value if the piece had been captured.  This technique had a serious drawback: it was impossible to promote a pawn to a piece which had not already been captured.  Later versions of the program fixed this problem.</li></ul> Today, this type of super-miserly structure would only be useful (maybe) if you wrote a chess program for a Palm Pilot, a cell phone or a set-top box where 80-90% of resources are consumed by the operating system and non-game services.  However, for some other types of games, there is really no alternative!<br />
<br />
 For more information on vintage chess programs, read David Welsh's book, <em class='bbc'>Computer Chess</em>, published in 1984.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Bit Boards</strong></span><br />
<br />
For many games, it is hard to imagine better representations than the simple one-square, one-slot array.  However, for chess, checkers and other games played on a 64-square board, a clever trick was developed (apparently by the KAISSA team in the Soviet Union) in the late 60's: the bit board.<br />
<br />
 KAISSA ran on a mainframe equipped with a 64-bit processor.  Now, 64 happens to be the number of squares on a chess board, so it was possible to use a single memory word to represent a yes-or-no or true-or-false predicate for the whole board.  For example, one bitboard might contain the answer to "Is there a white piece here?" for each square of the board.<br />
<br />
 Therefore, the state of a chess game could be completely represented by 12 bitboards: one each for the presence of white pawns, white rooks, black pawns, etc.  Adding two bitboards for "all white pieces" and "all black pieces" might accelerate further computations.  You might also want to hold a database of bitboards representing the squares attacked by a certain piece on a certain square, etc.; these constants come in handy at move generation time.<br />
<br />
 The main justification for bit boards is that a lot of useful operations can be performed using the processor's instruction set's 1-cycle logical operators.  For example, suppose you need to verify whether the white queen is checking the black king.  With a simple square-array representation, you would need to:<br />
 <ul class='bbc'><li>Find the queen's position, which requires a linear search of the array and may take 64 load-test cycles.</li><li>Examine the squares to which it is able to move, in all eight directions, until you either find the king or run out of possible moves.</li></ul> This process is always time-consuming, more so when the queen happens to be located near the end of the array, and even more so when there is no check to be found, which is almost always the case!<br />
<br />
 With a bitboard representation, you would:<br />
 <ul class='bbc'><li>Load the "white queen position" bitboard.</li><li>Use it to index the database of bitboards representing squares attacked by queens.</li><li>Logical-AND that bitboard with the one for "black king position".</li></ul> If the result is non-zero, then the white queen is checking the black king.  Assuming that the attack bitboard database is in cache memory, the entire operation has consumed 3-4 clock cycles!<br />
<br />
 Another example: if you need to generate the moves of the white knights currently on the board, just find the attack bitboards associated with the positions occupied by the knights and AND them with the logical complement of the bitboard representing "all squares occupied by white pieces" (i.e, apply the logical NOT operator to the bitboard), because the only restriction on knights is that they can not capture their own pieces!<br />
<br />
 For a (slightly) more detailed discussion of bitboards, see the article describing the CHESS 4.5 program developed at Northwestern University, in Peter Frey's book <em class='bbc'>Chess Skill in Man and Machine</em>; there are at least two editions of this book, published in 1977 and 1981.<br />
<br />
 Note: To this day, few personal computers use true 64-bit processors, so at least some of the speed advantages associated with bitboards are lost.  Still, the technique is pervasive, and quite useful.<br />
<br />
<br />
<span style='font-size: 18px;'><strong class='bbc'>Transposition Tables</strong></span><br />
<br />
In chess, there are often many ways to reach the same position.  For example, it doesn't matter whether you play 1. P-K4 ... 2. P-Q4 or 1. P-Q4... 2. P-K4; the game ends up in the same state.  Achieving identical positions in different ways is called <em class='bbc'>transposing</em>.<br />
<br />
 Now, of course, if your program has just spent considerable effort searching and evaluating the position resulting from 1. P-K4 ... 2. P-Q4, it would be nice if it were able to remember the results and avoid repeating this tedious work for 1. P-Q4... 2. P-K4.  This is why all chess programs, since at least Richard Greenblatt's Mac Hack VI in the late 1960's, have incorporated a <em class='bbc'>transposition table</em>.<br />
<br />
 A transposition table is a repository of past search results, usually implemented as a hash dictionary or similar structure to achieve maximum speed.  When a position has been searched, the results (i.e., evaluation, depth of the search performed from this position, best move, etc.) are stored in the table.  Then, when new positions have to be searched, we query the table first: if suitable results already exist for a specific position, we use them and bypass the search entirely.<br />
<br />
 There are numerous advantages to this process, including:<br />
 <ul class='bbc'><li>Speed.  In situations where there are lots of possible transpositions (i.e., in the endgame, when there are few pieces on the board), the table quickly fills up with useful results and 90% or more of all positions generated will be found in it.</li><li>Free depth.  Suppose you need to search a given position to a certain depth; say, four-ply (i.e., two moves for each player) ahead.  If the transposition table already contains a six-ply result for this position, not only do you avoid the search, but you get more accurate results than you would have if you had been forced to do the work!</li><li>Versatility.  Every chess program has an "opening book" of some sort, i.e., a list of well-known positions and best moves selected from the chess literature and fed to the program to prevent it from making a fool out of itself (and its programmer) at the very beginning of the game.  Since the opening book's modus operandi is identical to the transposition table (i.e., look up the position, and spit out the results if there are any), why not initialize the table with the opening book's content at the beginning of the game?  This way, if the flow of the game ever leaves the opening book and later translates back into a position that was in it, there is a chance that the transposition table will still contain the appropriate information and be able to use it.</li></ul> The only real drawback of the transposition table mechanism is its voracity in terms of memory.  To be of any use whatsoever, the table must contain several thousand entries; a million or more is even better.  At 16 bytes or so per entry, this can become a problem in memory-starved environments.<br />
<br />
 <strong class='bbc'>Other uses of transposition tables</strong><br />
CHESS 4.5 also employed hash tables to store the results of then-expensive computations which rarely changed in value or alternated between a small number of possible choices:<br />
 <ul class='bbc'><li>Pawn structure.  Indexed only on the positions of pawns, this table requires little storage, and since there are comparatively few possible pawn moves, it changes so rarely that 99% of positions result in hash table hits.</li><li>Material balance, i.e., the relative strength of the forces on the board, which only changes after a capture or a pawn promotion.</li></ul> This may not be as useful in these days of plentiful CPU cycles, but the lesson is a valuable one: some measure of pre-processing can save a lot of computation at the cost of a little memory.  Study your game carefully; there may be room for improvement here.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Generating Hash Keys for Chess Boards</strong></span><br />
<br />
The transposition tables described above are usually implemented as hash dictionaries of some sort, which brings up the following topic: how do you generate hashing keys from chess boards, quickly and efficiently?<br />
<br />
 The following scheme was described by Zobrist in 1970:<br />
 <ul class='bbc'><li>Generate 12x64 N-bit random numbers (where the transposition table has 2^N entries) and store them in a table.  Each random number is associated with a given piece on a given square (i.e., black rook on H4, etc.)  An empty square is represented by a null word.</li><li>Start with a null hash key.</li><li>Scan the board; when you encounter a piece, XOR its random number to the current hash key.  Repeat until the entire board has been examined.</li></ul> An interesting side effect of the scheme is that it will be very easy to update the hash value after a move, without re-scanning the entire board.  Remember the old XOR-graphics?  The way you XOR'ed a bitmap on top of a background to make it appear (usually in distorted colors), and XOR'ed it again to make it go away and restore the background to its original state?  This works similarly.  Say, for example, that a white rook on H1 captures a black pawn on H4.  To update the hash key, XOR the "white rook on H1" random number once again (to "erase" its effects), the "black pawn on H4" (to destroy it) and the "white rook on H4" (to add a contribution from the new rook position).<br />
<br />
 Use the exact same method, with different random numbers, to generate a second key (or "hash lock") to store in the transposition table along with the truly useful information.  This is used to detect and avoid collisions: if, by chance, two boards hash to the exact same key and collide in the transposition table, odds are extremely low that they will also hash to the same lock!<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>History Tables</strong></span><br />
<br />
The "history heuristic" is a descendant of the "killer move" technique.  A thorough explanation belongs in the article on search; for now, it will be sufficient to say that a history table should be maintained to note which moves have had interesting results in the past (i.e., which ones have cut-off search quickly along a continuation) and should therefore be tried again at a later time.  The history table is a simple 64x64 array of integer counters; when the search algorithm decides that a certain move has proven useful, it will ask the history table to increase its value.  The values stored in the table will then be used to sort moves and make sure that more "historically powerful" ones will be tried first.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Pre-processing move generation</strong></span><br />
<br />
Move generation (i.e., deciding which moves are legal given a specific position) is, with position evaluation, the most computationally expensive part of chess programming.  Therefore, a bit of pre-processing in this area can go a long way towards speeding up the entire game.<br />
<br />
 The scheme presented by Jean Goulet in his 1984 thesis <em class='bbc'>Data Structures for Chess</em> (McGill University) is a personal favorite.  In a nutshell:<br />
 <ul class='bbc'><li>For move generation purposes, piece color is irrelevant except for pawns which move in opposite directions.</li><li>There are 64 x 5 = 320 combinations of major piece and square from which to move, 48 squares on which a black pawn can be located (they can never retreat to the back rank, and they get promoted as soon as they reach the eight rank), and 48 where a white pawn can be located.</li><li>Let us define a "ray" of moves as a sequence of moves by a piece, from a certain square, in the same direction.  For example, all queen moves towards the "north" of the board from square H3 make up a ray.</li><li>For each piece on each square, there are a certain number of rays along which movement might be possible.  For example, a king in the middle of the board may be able to move in 8 different directions, while a bishop trapped in a corner only has one ray of escape possible.</li><li>Prior to the game, compute a database of all rays for all pieces on all squares, assuming an empty board (i.e., movement is limited only by the edges and not by other pieces).</li><li>When you generate moves for a piece on a square, scan each of its rays until you either reach the end of the ray or hit a piece.  If it is an enemy piece, this last move is a capture.  If it is a friendly piece, this last move is impossible.</li></ul> With a properly designed database, move generation is reduced to a simple, mostly linear lookup; it requires virtually no computation at all.  And the entire thing holds within a few dozen kilobytes; mere chump change compared to the transposition table!<br />
<br />
 All of the techniques described above (bit boards, history, transposition table, pre-processed move database) will be illustrated in my own chess program, to be posted when I finish writing this series.  Next month, I will examine move generation in more detail.<br />
<br />
<em class='bbc'> François Dominic Laramée, June 2000</em>]]></description>
		<pubDate>Sun, 11 Jun 2000 11:21:09 +0000</pubDate>
		<guid isPermaLink="false">9ff2d68a234ace2643d46c35b9002ab3</guid>
	</item>
	<item>
		<title>Chess Programming Part I: Getting Started</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/chess-programming-part-i-getting-started-r1014</link>
		<description><![CDATA[This is the first article in a six-part series about programming computers to play chess, and by extension other similar strategy games of perfect information.<br />
<br />
 Chess has been described as the <em class='bbc'>Drosophila Melanogaster</em> of artificial intelligence, in the sense that the game has spawned a great deal of successful research (including a match victory against the current world champion and arguably the best player of all time, Gary Kasparov), much like many of the discoveries in genetics over the years have been made by scientists studying the tiny fruit fly.  This article series will describe some of the state-of-the-art techniques employed by the most successful programs in the world, including Deep Blue.<br />
<br />
 Note that by the time the series is completed (in October), I will have written a simple implementation of the game in Java, and the source code will be freely available for download on my web site.  So if you want to see more code samples, be patient; I'll give you plenty in due time!<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Games of Perfect Information</strong></span><br />
<br />
Chess is defined as a game of "perfect information", because both players are aware of the entire state of the game world at all times: just by looking at the board, you can see which pieces are alive and where they are located.  Checkers, Go, Go-Moku, Backgammon and Othello are other members of the category, but stud poker is not (you don't know what cards your opponent is holding in his hands).<br />
<br />
 Most of the techniques described in this series will apply more or less equally to all games of perfect information, although the details will vary from game to game.  Obviously, while a search algorithm is a search algorithm no matter what the domain, move generation and position evaluation will depend completely on the rules of the game being played!<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>What We Need</strong></span><br />
<br />
In order to play chess, a computer needs a certain number of software components.  At the very least, these include:<br />
 <ul class='bbc'><li>Some way to represent a chess board in memory, so that it knows what the state of the game is.</li><li>Rules to determine how to generate legal moves, so that it can play without cheating (and verify that its human opponent is not trying to pull a fast one on it!)</li><li>A technique to choose the move to make amongst all legal possibilities, so that it can choose a move instead of being forced to pick one at random.</li><li>A way to compare moves and positions, so that it makes intelligent choices.</li><li>Some sort of user interface.</li></ul> This series will cover all of the above, except the user interface, which is essentially a 2D game like any other.  The rest of this article describes the major issues related to each component and introduces some of the concepts to be explored in the series.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Board Representations</strong></span><br />
<br />
In the early days of chess programming, memory was extremely limited (some programs ran in 8K or less) and the simplest, least expensive representations were the most effective.  A typical chessboard was implemented as an 8x8 array, with each square represented by a single byte: an empty square was allocated value 0, a black king could be represented by the number 1, etc.<br />
<br />
 When chess programmers started working on 64-bit workstations and mainframes, more elaborate board representations based on "bitboards" appeared.  Apparently invented in the Soviet Union in the late 1960's, the bit board is a 64-bit word containing information about one aspect of the game state, at a rate of 1 bit per square.  For example, a bitboard might contain "the set of squares occupied by black pawns", another "the set of squares to which a queen on e3 can move", and another, "the set of white pieces currently attacked by black knights". Bitboards are versatile and allow fast processing, because many operations that are repeated very often in the course of a chess game can be implemented as 1-cycle logic operations on bitboards.<br />
<br />
 Part II of this series covers board representations in detail.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Move Generation</strong></span><br />
<br />
The rules of the game determine which moves (if any) the side to play is allowed to make.  In some games, it is easy to look at the board and determine the legal moves: for example, in tic-tac-toe, any empty square is a legal move.  For chess, however, things are more complicated: each piece has its own movement rules, pawns capture diagonally and move along a file, it is illegal to leave a king in check, and the "en passant" captures, pawn promotions and castling moves require very specific conditions to be legal.<br />
<br />
 In fact, it turns out that move generation is one of the most computationally expensive and complicated aspects of chess programming.  Fortunately, the rules of the game allow quite a bit of pre-processing, and I will describe a set of data structures which can speed up move generation significantly.<br />
<br />
 Part III of this series covers this topic.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Search Techniques</strong></span><br />
<br />
To a computer, it is far from obvious which of many legal moves are "good" and which are "bad".  The best way to discriminate between the two is to look at their consequences (i.e., search series of moves, say 4 for each side and look at the results.)  And to make sure that we make as few mistakes as possible, we will assume that the opponent is just as good as we are.  This is the basic principle underlying the minimax search algorithm, which is at the root of all chess programs.<br />
<br />
 Unfortunately, minimax' complexity is O(b<sup class='bbc'>n</sup>), where b ("branching factor") is the number of legal moves available on average at any given time and n (the depth) is the number of "plies" you look ahead, where one ply is one move by one side.  This number grows impossibly fast, so a considerable amount of work has been done to develop algorithms that minimize the effort expended on search for a given depth.  Iterative-deepening Alphabeta, NegaScout and MTD(f) are among the most successful of these algorithms, and they will be described in Part IV, along with the data structures and heuristics which make strong play possible, such as transposition tables and the history/killer heuristic.<br />
<br />
 Another major source of headaches for chess programmers is the "horizon effect", first described by Hans Berliner.  Suppose that your program searches to a depth of 8-ply, and that it discovers to its horror that the opponent will capture its queen at ply 6.  Left to its own devices, the program will then proceed to throw its bishops to the wolves so that it will delay the queen capture to ply 10, which it can't see because its search ends at ply 8.  From the program's point of view, the queen is "saved", because the capture is no longer visible...  But it has lost a bishop, and the queen capture reappears during the next move's search.  It turns out that finding a position where a program can reason correctly about the relative strength of the forces in presence is not a trivial task at all, and that searching every line of play to the same depth is tantamount to suicide.  Numerous techniques have been developed to defeat the horizon effect; quiescence search and Deep Blue's singular extensions are among the topics covered in Part V on advanced search.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Evaluation</strong></span><br />
<br />
Finally, the program must have some way of assessing whether a given position means that it is ahead or that it has lost the game.  This evaluation depends heavily upon the rules of the game: while "material balance" (i.e., the number and value of the pieces on the board) is the dominant factor in chess, because being ahead by as little as a single pawn can often guarantee a victory for a strong player, it is of no significance in Go-Moku and downright misleading in Othello, where you are often better off with fewer pieces on the board until the very last moment.<br />
<br />
 Developing a useful evaluation function is a difficult and sometimes frustrating task.  Part VI of this series covers the efforts made in that area by the developers of some of the most successful chess programs of all time, including Chess 4.5, Cray Blitz and Belle.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Conclusion</strong></span><br />
<br />
Now that we know which pieces we will need to complete the puzzle, it is time to get started on that first corner.  Next month, I will describe the most popular techniques used to represent chess boards in current games.  See you there!<br />
 <br />
<br />
<em class='bbc'> François Dominic Laramée, April 2000</em>]]></description>
		<pubDate>Wed, 17 May 2000 19:30:33 +0000</pubDate>
		<guid isPermaLink="false">9ed6f34466ebc301e3f09c1dedb6cfb2</guid>
	</item>
	<item>
		<title>A Practical Guide to Building a Complete Game A...</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/a-practical-guide-to-building-a-complete-game-a-r785</link>
		<description><![CDATA[Artificial Intelligence (AI) is based on making intelligent looking decisions, for the units in our games to look intelligent they have to perform actions that seem reasonable for the situations they are in.<br />
<br />
 In a Real-Time Strategy (RTS) type game these actions would consist of moving, patrolling, avoiding obstacles, targeting enemies and pursuing them. Lets take a look at what it would take to implement each of these actions.<br />
<br />
 <span style='font-size: 18px;'><strong class='bbc'>Movement</strong></span><br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[bde0b24fb444463b837efafbef9d6f90]' id='ipb-attach-url-2710-0-83957600-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2710" title="moving.jpg - Size: 25.16K, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-55619400-1307095318_thumb.jpg" id='ipb-attach-img-2710-0-83957600-1330207785' style='width:246;height:200' class='attach' width="246" height="200" alt="Attached Image: moving.jpg" /></a> </p><br />
  Moving, in its most basic form, consists of simply advancing from one set of coordinates to another set over a period of time. This can be performed easily by finding a distance vector and multiplying it by the speed the unit is moving and the time since we last calculated the position.<br />
<br />
 Because we are working from a mouse based input system, we don't expect the user to have to make all the movements around obstacles like they would in a joystick or first-person shooter. The way to keep the user from having to click their way around obstacles is to create an action queue so that we can have more than one action in a row completed. This way if a path has to avoid an obstacle we can add the additional paths in front of the final destination to walk the unit around the obstacle without player intervention.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Patrolling</strong></span><br />
 <br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[bde0b24fb444463b837efafbef9d6f90]' id='ipb-attach-url-2711-0-83976200-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2711" title="patrol.jpg - Size: 27.65K, Downloads: 41"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-57680900-1307095340_thumb.jpg" id='ipb-attach-img-2711-0-83976200-1330207785' style='width:250;height:149' class='attach' width="250" height="149" alt="Attached Image: patrol.jpg" /></a></p><br />
 Patrolling consists of moving to a series of specified positions in order. At the time when a unit has moved to a destination and has nowhere else to go, we can compare his current position to his list of patrol points and set a new destination to the one after where he is closest to.<br />
<br />
 There isn't a lot to this, but having units moving on the screen, as opposed to standing still and waiting, makes the world look a lot more alive and gives them a lot less chance of being snuck up on and catching intruders.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Obstacle Avoidance</strong></span><br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[bde0b24fb444463b837efafbef9d6f90]' id='ipb-attach-url-2712-0-83990200-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2712" title="obstacles.jpg - Size: 34.59K, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-51772600-1307095366_thumb.jpg" id='ipb-attach-img-2712-0-83990200-1330207785' style='width:128;height:200' class='attach' width="128" height="200" alt="Attached Image: obstacles.jpg" /></a><br />
</p><br />
  Avoidance algorithms require the understanding of how your maps are going to work and how you want your units to interact with them while moving around. In our case we are going to assume an outdoor environment with relatively small and simple obstacles such as small buildings and objects. We will also assume that you cannot go inside an obstacle and that obstacles are convex polygons with 4 vertices.<br />
<br />
 In an environment such as this we are mostly dealing with open movement and obstacles that have to be avoided can be with only 1-2 avoidance movements.<br />
<br />
<p class='bbc_center'> <a class='resized_img' rel='lightbox[bde0b24fb444463b837efafbef9d6f90]' id='ipb-attach-url-2713-0-84001300-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2713" title="action_queue.jpg - Size: 24.76K, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-98675700-1307095388_thumb.jpg" id='ipb-attach-img-2713-0-84001300-1330207785' style='width:191;height:200' class='attach' width="191" height="200" alt="Attached Image: action_queue.jpg" /></a></p> <br />
 In the example to the left we have a very thin 4 point poly that is between the unit and the destination. In this case we move away from the closest vertex to the destination and move several units away in the perpendicular angle from the unit's collision. This gives us the buffer space we need to move around the obstacle.<br />
<br />
 Obstacle avoidance has to be determined by the type of the obstacles you are going to be providing. In this simple example we are going to use convex 4 point polygons, which will usually be in a diamond or square shape. Because of these obstacle limitations we can simply find the edge closest to the destination which the unit trying to get to and move out from the obstacle a little thereby creating a simple way to avoid obstacles which works fairly well as long as obstacles dont get too close together.<br />
<br />
 When you want to get into some more advanced path finding algorithms, you should look into A*, which is a popular algorithm for finding the shortest path through very maze-like areas. Beyond A* there are various steering algorithms for gradually moving around obstacles and other more hard-coded situations such as creating funneling intersections that can be used to get to different areas of the map.<br />
<br />
 <br clear="all"> <span style='font-size: 18px;'><strong class='bbc'>Targeting Enemies</strong></span><br />
 <br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[bde0b24fb444463b837efafbef9d6f90]' id='ipb-attach-url-2714-0-84012100-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2714" title="aiming.jpg - Size: 28.3K, Downloads: 38"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-88093000-1307095426_thumb.jpg" id='ipb-attach-img-2714-0-84012100-1330207785' style='width:211;height:200' class='attach' width="211" height="200" alt="Attached Image: aiming.jpg" /></a></p><br />
 Targeting for other units will greatly depend on what you want your player to be doing in your game. You may want your player's units to automatically fire on enemies they see, so that player can devote themselves to the big picture. You may want your units to only attack if specifically told to keep your player's attention on the units and their surroundings.<br />
<br />
 Either way, you will want your enemies to be on the look out for the player's units to provide the challenge of on-the-ball enemies.<br />
<br />
 In a situation where you have split up your directions 8 ways, you can assume that for a unit to be facing another unit, within vision range, they must be either directly in front of the unit or in one of the adjacent directions. A simple test to determine if the unit is within maximum sight distance and is in one of these three directions from the unit can give you good result with a minimal amount of time to test cases.<br />
<br />
 Of course you will want to add in a test for obstacles to see if the units are blocked, most likely you can use the same test for obstacle avoidance for this, as you usually either have a clear path or not . Adding in height to visibility testing will of course totally change the nature of these tests, but that is for another article.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Pursuit</strong></span><br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[bde0b24fb444463b837efafbef9d6f90]' id='ipb-attach-url-2715-0-84022700-1330207785' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2715" title="pursuit.jpg - Size: 22.07K, Downloads: 31"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-46181700-1307095452_thumb.jpg" id='ipb-attach-img-2715-0-84022700-1330207785' style='width:142;height:200' class='attach' width="142" height="200" alt="Attached Image: pursuit.jpg" /></a></p><br />
Once your enemies have found a target, you won't want them to just wander around aimlessly if they lose sight of their prey. At this point you need to make a choice about how you wish to handle your searching though. Up until now we have only talked about spotting units based on actually being able to see them. In some cases this may get a little tricky when pursuing an enemy, so you may opt to cheat and just set the destination of the unit being tracked as the tracker's destination.<br />
<br />
  If you wish to keep things more realistic and do less "cheating", then you need to store the last position the target was seen in to give a place to start searching for them. For our example we will just take a random search approach. First you would set the last position the target was seen as the first destination. Then as the next destination you would make a random distance in the direction that the target was originally from the unit before he lost sight of the target.<br />
<br />
 In this way we assume that the target ran away from the unit and if we are correct, the unit will hopefully find him quickly after passing the first destination. In case the unit did not find his target, we can make a back up plan of setting a patrol at random distances around where the first destination was. So the unit will go back to the spot his target was last seen and will walk in a pattern searching for him.<br />
<br />
 While this doesn't cover a lot of possibilities, it does give us a reasonable response given the situation.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Conclusion</strong></span><br />
<br />
The secret to implementing all game AI is the understanding the cases you are trying to deal with and the results of what you want it to look like. If you can picture what you want the actions to look like and formulate an algorithm to make them turn out that way you are 90% of the way done. However the last 10%, getting it to work, can easily take 10 times as long as figuring out how to do it…<br />
<br />
<a href='mailto:ghowland@lupinegames.com' title='E-mail Link' class='bbc_email'>-Geoff Howland</a><br />
<a href='http://www.lupinegames.com/' class='bbc_url' title='External link' rel='nofollow external'>Lupine Games</a><br />
<br />
 <br />
The first article: <a href='http://www.gamedev.net/reference/articles/article784.asp' class='bbc_url' title=''>Practical Guide to Building a Complete Game AI: Volume I</a>]]></description>
		<pubDate>Tue, 12 Oct 1999 15:35:56 +0000</pubDate>
		<guid isPermaLink="false">393c55aea738548df743a186d15f3bef</guid>
	</item>
	<item>
		<title>A Practical Guide to Building a Complete Game A...</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/a-practical-guide-to-building-a-complete-game-a-r784</link>
		<description><![CDATA[Artificial Intelligence (AI) in games has taken the backseat in development for a long time for many reasons but the future of games is definitely going to be weighted heavily with increasingly detailed game AI. If your game's AI is not up to the current level that game player's expectations demand then your game will feel dated and suffer for it in their opinions.<br />
<br />
 Game AI is not just neural networks and learning systems and complex mathematical structures, although it can be, but primarily game AI is about creating an environment and the appearance of thought from units. Game AI is behavioral, not scientific.<br />
<br />
 The key to understanding how to create game AI is understanding what you want your final results to be and then building the system to provide those results. It all comes down to what the player can see; if they can't tell it's happening, then it might as well not be.<br />
<br />
<em class='bbc'> The examples and discussion will be given based on the format of Real-Time Strategy (RTS) games, however some of these concepts can be translated into being appropriate for other genres as well. All data examples are done in standard C format.</em><br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>State Machines</strong></span><br />
 <br />
<span style='font-size: 12px;'><strong class='bbc'>Finite State Machine</strong></span><br />
<br />
A finite state machine (FSM) is a system that has a limited number of states of operation. A real world example could be a light switch which is either on or off, or an alarm clock that is either idling by telling time, ringing an alarm or having its time or alarm set. Any system that has a limited number of possibilities where something can be defined by one state (even combinations) can be represented as a finite state machine.<br />
<br />
 Finite state machines are natural for any type of computer program and understanding how to use them effectively to create game AI is only as hard as understanding the system you are trying to represent, which is as detailed or simple as you make it.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Using Finite State Machines</strong></span><br />
<br />
There are many purposes for using FSMs in games but one of the more intricate ones you have to deal with is trying to model unit behavior since trying to simulate human beings is the toughest simulation there is. As guaranteed hard as it is to simulate human behavior there have been many stories of detailed game AI's that were mistaken for human players and vice versa by other players and spectators of the games, especially some detailed FSMs systems.<br />
<br />
 While some other systems are designed to more accurately model the way humans think and learn, sometimes you can just never beat the simplicity of having a choice, weighing the factors and deciding, as a human, which one you would make given that choice. When learning more about AI decision and learning systems always keep this in mind as often the best system for the job is the simplest and not the most scientifically accurate.<br />
<br />
 Don’t misunderstand this as opposition to Neural Network, Genetic Algorithms or any other artificial intelligence systems, just don’t mistake clever routines and interesting algorithms as being a better solution if they wont give better results. Weigh your choices based off what you need to get your end result, not the latest trends.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Game State Machines</strong></span><br />
<br />
Creating a believable environment for your game means that you need to consider as many detailed elements that the player might possibly focus their attention on as you can. The more of these you anticipate by planning and testing, the more immersive the environment will be for the player when they are discovering your creation.<br />
<br />
 In your total game state there will be at least two division of state machines that you will need to keep your game going. The first state machine will deal with the game interface, which includes whether the game is paused, if there are different modes the player can be looking at the world in, then which one, what things the player can and can't see and any other flags you might use for your particular interface.<br />
<br />
 The second state machine will deal with what is actually going on in the game, the current state of the environment, objects in the level, objectives completed or failed in the mission and all other variables that you use to guide and challenge the player.<br />
<br />
 You may have an alert system where the enemies will be actively patrolling if the player has been spotted or has fired shots, or flags for whether certain critical pieces have been destroyed or not. All of these items can be contained inside of a structure such as the example one below.<br />
<br />
 [indent]<pre class='prettyprint'>struct GameLevelState {<br />  int alert;        	// Alert status of enemies //<br />  struct Positionshot;  // Position of last shot fired //<br />  int shotTime;     	// Game cycle last shot was fired //<br />  int hostage;      	// Hostage rescued //<br />  int explosives;   	// Explosives set or not //<br />  int tank;         	// Tank destroyed //<br />  int dialogue;     	// Dialogue variable //<br />  int complete;     	// Mission completed //<br /> };</pre><br />
[/indent]<span style='font-size: 12px;'> <strong class='bbc'>Flexibility</strong></span><br />
<br />
Keeping your AI flexible is extremely important. The more modular you make your routines, the more you will be able to expand them as you go on. Its important to understand that designing a game AI is very much an iterative process, you need to try things out and build upon them.<br />
<br />
 The goal in creating a good AI is to have units that react in situations that seem realistic in an environment they seem to be interacting with. If you box in what your units will be able to do too early it will be difficult to expand the breadth of their actions later on when you decide to augment the game world to feel more complete or interactive.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Unit Actions</strong></span><br />
<br />
In a game where the player controls units, it is all important to have meaningful and well organized information on them. Without this, adapting the units to the players will become difficult and the users interface with the game could suffer. If the player doesn’t feel he is controlling the units and getting appropriate information back from them, then all he is doing is clicking around in an interface and all immersive aspects the game held will be lost. Meaning the player won't be having any fun and could be becoming frustrated.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Anatomy 101</strong></span><br />
<br />
To get a sense of what kind of information you may want to provide to the player with let's take a look at a sample data structure.<br />
<br />
 [indent]<pre class='prettyprint'>struct Character {<br />  struct Positionpos;           	// Map position //<br />  int screenX, screenY;         	// Screen position //<br />  int animDir, animAction, animNum; // Animation information, action and animation frame number //<br />  int rank;                     	// Rank //<br />  int health;                   	// Health //<br />  int num;                      	// Number of unit //<br />  int group;                    	// Group number //<br />  int style;                    	// Style of unit (elf, human) //<br />  struct AnimationObject animObj;   // Animation object for complex animations //<br />};</pre><br />
[/indent] Now some definitions of the variables:<br />
<br />
 The <em class='bbc'>pos</em> variable determines the unit's position in the game world and the <em class='bbc'>screenX, screenY</em> variables are useful for easily adding information around the unit on the screen such as health or selection information.<br />
<br />
 The <em class='bbc'>animDir, animAction and animNum</em> all refer to the units current animated state that will be drawn to the screen.<br />
<br />
 The <em class='bbc'>rank</em> and <em class='bbc'>health</em> variables are both fairly obvious and are extremely simplified for what information they could hold.<br />
<br />
 The <em class='bbc'>num</em> variable is the number that the unit is in the main unit array. Later, when calling the unit information from its group it is sometimes useful to pass off which unit it is, without giving the actual structure address.<br />
<br />
 The <em class='bbc'>group</em> variable determines which group the unit belongs to as a unit should belong to a group at almost all times. The only time a unit should not be in a group is if the unit is dead.<br />
<br />
 The <em class='bbc'>style</em> and <em class='bbc'>animObj</em> variables are both more information about how the unit's graphics will be drawn.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Building Past Basics</strong></span><br />
<br />
Once you have your initial routines working based on a simple version of your units, such as the above, its time to start building more information into them to really bring them to life.<br />
<br />
 You will need to think about what kind of actions and reactions you want the units to have. Do you want them to be controlled by emotions? Do you want them to be able to freeze up? Run away? Charge like a madman?<br />
<br />
 If you do then adding variables to determining emotional states could be a next step. The best way to try to understand what components your units can have is to try and understand yourself and what you would be dealing with in a situation that they are. In order to create human like reactions, you need to base it off of how a human would react.<br />
<br />
 There is another side to this, almost an opposite of human reaction, which is providing a synthetic experience that is not based on reality, but instead based on challenging the player. Instead of making your units based on your instincts, you will need to think in whatever manner you want your units to react in. The point is that you have to make the decisions about every facet you can or you will end up with flat, boring reactions that are too easy to predict, or even seemingly random. Either of these traits could ruin an otherwise good game, so put a lot of thought into it, and most importantly, play it to death to make sure it works!<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Grouping</strong></span><br />
 <br />
<span style='font-size: 12px;'><strong class='bbc'>To group or not to group?</strong></span><br />
<br />
If you are creating a First Person Shooter game then it comes as no big surprise that grouping isn't for you. However, if you are creating a RTS or a game that has the player controlling more than one unit at a time then you have a question to ask yourself.<br />
<br />
 Do you need your units to act in a coordinated way?<br />
<br />
 If the answer is yes, then there is a good chance that grouping is for you. If the answer is no there still may be advantages to grouping but you will have to sort those out on your own as they will no doubt be totally dependent on exactly the kind of actions you want your units to perform.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Benefits of Grouping</strong></span><br />
 <ul class='bbcol decimal'><li>Units can move in a formation only accessing one master list of movement information. The advantage here is that you do not have to propagate information to every unit in the group when a destination or target changes as they all get their movement information off of the group source.</li><li>Multi-unit coordinated actions, such as surrounding a building, can be controlled at a central location instead of each unit trying to work out where it is in relation to other units and bumping back and forth until they are in the correct position.</li><li>Groups can maintain their structure so that issuing new orders only takes the same amount of time and data as issuing an order to a single unit. Most important you will create something that can be easily understood and read. Changing around 25 units or so and having them try to pass information to each other can be quite a chore if they don’t have any common ground.</li><li>Depending on the formation of the group, obstacle avoidance and detection can be simplified and time to find paths can be reduced, which can be a serious concern when dealing with a large amount of units.</li></ul> <span style='font-size: 12px;'><strong class='bbc'>The Big Picture</strong></span><br />
<br />
Organizing your group, just like everything else in creating a game AI, is about understand the final affect you want to gain with control of the units. The idea is to create a place where there is a central repository of information which can be found quickly and shared between units. The idea is also not to duplicate any data, you want data to be found at one source and one source only, and that source needs to be the most logical position for the information so that when you are later working with it and building off of it, other logical extensions will equally seem to be in the correct places.<br />
<br />
 From my experience I decided that this separation in my work should be split where anything that has to do with the unit as an enclosed entity will be placed in the unit's data structure, while anything that had to do with movement, or actions, since those are what we are trying to organize and share, will be placed in the group data structures.<br />
<br />
 This means that the units alone will not have any information on where they are going, or what they are doing beyond the physical position they are in, like their animation frame and position in the world. To do this it means that a unit must ALWAYS be in a group as long as they are capable of moving or their actions changing. If they are alone, then they are just a group of one.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>One of many</strong></span><br />
<br />
While we are ultimately looking for a group to act as a coordinated system, the system is definitely made up of individual pieces and it's important to keep track of what each unit is doing individually so that when we need the group to break formation and move about as separate entities with common or individual purposes we can. For this goal I created a structure similar to the one below.<br />
<br />
 [indent]<pre class='prettyprint'>struct GroupUnit {<br />  int unitNum;              	// Character Number //<br />  struct Unit *unit;        	// Unit character data //<br />  struct Positionwaypoint&#91;50&#93;;  // Path in waypoints for units //<br />  int action&#91;50&#93;;           	// Actions by waypoints //<br />  int stepX, stepY;         	// Step for individual units, when in cover mode // <br />  int run, walk, sneak, fire, hurt, sprint, crawl;      	// Actions //<br />  int target;               	// Targets for units //<br />  struct Position targetPos;	// Target Position //<br />};</pre>[/indent] Explanations of the variables:<br />
<br />
 The <em class='bbc'>unitNum</em> is the number of the unit in the group. If there is a maximum of 10 units in a group, then there will be 10 possible slots that could have units. The first unit would be unitNum 0, following to unitNum 9.<br />
<br />
 The <em class='bbc'>unit</em> is a pointer to the unit's character data, which holds information like the characters current position, health and every other piece of information on the individual. Its important that a unit's vital signs and other information can be monitored from the group so that you can easily check to see if a group member has been wounded and communicate this to the other members, along with a myriad of other possibilities.<br />
<br />
 The <em class='bbc'>waypoint</em> array contains all the places that the unit has to move in a queue. All actions and waypoints are only specified in the GroupUnit structure if the group is not in a formation and units need to move about on their own.<br />
<br />
 The <em class='bbc'>action</em> array contains actions that are associated with the movements to waypoints. This allows you to create more detailed command chains, as telling units to sneak across one area and then sprint across another adds a lot of possibilities to making more strategic and thought out movements by the player.<br />
<br />
 The <em class='bbc'>stepX, stepY</em> information can be used for simple velocity; every frame move this unit this many world-position-units in any direction on the map. Used properly this can be just as applicable for all situations as doing real physics modeling, only with a simpler system and usually reduced processing time (not to mention ease of implementing the first time or quickly).<br />
<br />
 The <em class='bbc'>run, walk, sneak…</em>variables all deal with different states the unit are in. These are not animations, but action states that can be toggled easily and even have multiple states that effect each other differently when more than one are turned on.<br />
<br />
 The <em class='bbc'>target</em> and <em class='bbc'>targetPos</em> variables are used to hold the unit number of the enemy being targeted and his current position. The enemies position, as well as health and other attributes, could just be referenced each time by looking up the enemies unit number, but for readability I decided it would be easier to keep a local copy of the enemies position.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Mob mentality</strong></span><br />
<br />
The ultimate goal of course is to have a centralized location for as much of the data as possible to limit the amount of look ups and processing to a minimum and keep things simple. Lets take a look at a sample data structure for doing this.<br />
<br />
 [indent]<pre class='prettyprint'>struct Group {<br />  int numUnits;          	// Units in group //<br />  struct GroupUnit unit&#91;4&#93;;  // Unit info //<br />  int formation;         	// Formation information for units and group //<br />  struct Position destPos;   // Destination (for dest. circle) //<br />  int destPX, destPY;    	// Destination Screen Coords //<br />  struct Position wayX&#91;50&#93;;  // Path in waypoints for group //<br />  float formStepX, formStepY;  // Formation step values for group movements //<br />  int formed;            	// If true, then find cover and act as individuals, otherwise move in formation //<br />  int action, plan;      	// Group action and plans //<br />  int run, walk, sneak, sprint, crawl, sniper;   // Actions //<br />  struct Position spotPos;   // Sniper Coords //<br />  int strategyMode;      	// Group strategy mode //<br />  int orders&#91;5&#93;;         	// Orders for group //<br />  int goals&#91;5&#93;;          	// Goals for group //<br />  int leader;            	// Leader of the group //<br />  struct SentryInfo sentry;  // Sentry List //<br />  struct AIStateaiState; 	// AI State //<br />};</pre><br />
[/indent] The <em class='bbc'>numUnits</em> variable refers to the number of units in the group and the <em class='bbc'>unit</em> array holds the GroupUnit information. For this particular group the maximum units has been hard coded to 4.<br />
<br />
 The <em class='bbc'>formation</em> flag determines what type of formation the group is in. They could be formed in a column, wedge or diamond shape easily by just changing this variable and letting the units reposition themselves appropriately.<br />
<br />
 The <em class='bbc'>destPos</em> and <em class='bbc'>destPX,destPY</em> are all information for keeping track of the final destination of the group and relaying that information quickly to the player. The waypoints and steps work the same manner as individuals except that when units are in a formation they will all have the same speed so they stay in formation. There is no need to update each unit by its own speed value, as the group's can be used.<br />
<br />
 The <em class='bbc'>formed</em> variable is one of the most important as it determines whether the units act in formation or as individuals. The concept is that if the group is formed then all the units will have the same operations performed on them each cycle. If there is a reason that they can't all move the same way, such as enemies attacking or a necessary break in formation to get past an obstacle, then the units need to move on their own.<br />
<br />
 The actions are the same as individual, and you'll notice that there is a variable for a sniper that is not in GroupUnit structure as there is no reason to have one unit in a group be a sniper while the rest are off running around. It is logical to split that unit into its own group and then control the sniper activities at the group level. This is the kind of planning you need to do to figure out what information is best served in what section of your structures.<br />
<br />
 The <em class='bbc'>strategyMode</em> is a quick variable that determines how the units respond to enemies. Is it aggressive, aggressive with cause, defensive, or run-on-sight? Having an easy to access overview variable that controls basic responses is a good way to cut out a lot of individual unit and group situation calculations. Beyond that it gives the control to the player, who can set different groups in different modes so they know how each group will react if they encounter any enemies.<br />
<br />
 The <em class='bbc'>orders</em> and <em class='bbc'>goals</em> arrays point to orders and goals described in an order and goal database so that when orders are given they can be assigned to multiple groups easily and each group feeds off the same information.<br />
<br />
 The <em class='bbc'>sentry</em> and <em class='bbc'>aiState</em> are fairly self explanatory as they contain sentry information and more detailed aiState information for doing detailed pattern matching.<br />
<br />
 <span style='font-size: 12px;'><strong class='bbc'>Putting it together</strong></span><br />
<br />
Now that we have some structures for our groups, what's next? The next step is to figure out how you are going to use this information by routines in your game.<br />
<br />
 It's <strong class='bbc'><em class='bbc'>crucial</em></strong> that you carefully plan for your AI routines to be modular and flexible so that you can add on to them later and easily call different pieces. The concept here, as in data structure organization, is to only do something in one function, and to make that function limited so that it does a specific thing. Then if you need to do that thing again you can call the routine that is already tested and is a known single point of operation on that data. Later if you run into problems with your AI and need to debug it, you don’t have to go hunting all over the place for the offending routine, because there is only one routine that would operate on that data, or at least in that manner.<br />
<br />
 <br />
<span style='font-size: 18px;'><strong class='bbc'>Tips</strong></span><br />
<br />
Walk before you run. Learn the basics, create the basics, add more advanced routines for your particular game as you need them. Never fall into the trap of using a routine because it is popular and everyone else seems to be using it. Often other people are using a routine because its' benefits fit their needs, but it may not fit yours. Furthermore, people often use routines just because they are the standard, even if they are actually not the best routines for their situation.<br />
<br />
 Your concern should always be on getting the best results, not having the current fashionable routines; if it works, use it. The game developer mantra used to be, and always should be, "If it looks right, it is right." Don’t let the people who are interested in designing real world total physics simulations make you feel bad for creating a simple positional system where you add X to the position each frame. If that is what works in your particular situation, then do it. Correct physics has its place in some games, but not all of them and there are other ways of achieving nearly the same results.<br />
<br />
 You can never build a perfect replica of reality. That is just a fact. So you need to draw your own line on where <em class='bbc'>good enough</em> is and then make your good enough reality.<br />
<br />
<a href='http://www.gamedev.net/reference/articles/article785.asp' class='bbc_url' title=''>Volume II: Unit Goals and Path Finding</a>]]></description>
		<pubDate>Tue, 12 Oct 1999 14:54:07 +0000</pubDate>
		<guid isPermaLink="false">365d17770080c807a0e47ae9118d8641</guid>
	</item>
	<item>
		<title>Neural Netware</title>
		<link>http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/neural-netware-r771</link>
		<description><![CDATA[<span style='font-size: 18px;'> <strong class='bbc'>And There Was Light...</strong></span><br />
<br />
The funny thing about high  technology is that sometimes it's hundreds of years old! For example,  Calculus was independently invented by both Newton and Leibniz over 300  years ago. What used to be magic, is now well known. And of course we  all know that geometry was invented by Euclid a couple thousand years  ago. The point is that many times it takes years for something to come  into "vogue". <em class='bbc'>Neural Nets</em> are a prime example. We all have heard  about neural nets, and about what their promises are, but we don't  really see too many real world applications such as we do for <em class='bbc'>ActiveX</em> or the <em class='bbc'>Bubblesort.</em>  The reason for this is that the true nature of neural nets is extremely  mathematical and understanding and proving the theorems that govern  them takes Calculus, Probability Theory, and Combinatorial Analysis not  to mention Physiology and Neurology. <br />
<br />
The key to unlocking any technology is for a person or persons to create a Killer App for it. We all know how <em class='bbc'>DOOM</em>  works by now, i.e. by using BSP trees. However, John Carmack didn't  invent them, he read about them in a paper written in the 1960's. This  paper described BSP technology. John took the next step an realized what  BSP trees could be used for and <em class='bbc'>DOOM</em> was born. I suspect that  Neural Nets may have the same revelation in the next few years.  Computers are fast enough to simulate them, VLSI designers are building  them right into the silicon, and there are hundreds of books that have  been published about them. And since Neural Nets are more mathematical  entities then anything else, they are not tied to any physical  representation, we can create them with software or create actual  physical models of them with silicon. The key is that neural nets are  abstractions or models. <br />
<br />
In many ways the computational limits of  digital computers have been realized. Sure we will keep making them  faster, smaller and cheaper, but digital computers will always process  digital information since they are based on deterministic binary models  of computation. Neural nets on the other hand are based on different  models of computation. They are based on highly parallel, distributed,  probabilistic models that don't necessarily model a solution to a  problem as does a computer program, but model a network of cells that  can find, ascertain, or correlate possible solutions to a problem in a  more biological way by solving the problem a in little pieces and  putting the result together. This article is a whirlwind tour of what  neural nets are, and how they work in as much detail as can be covered  in a few pages. I know that a few pages doesn't do the topic justice,  but maybe we can talk the management into a small series???<br />
<br />
<p class='bbc_center'><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2693-0-56849500-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2693" title="Image14.jpg - Size: 26.27K, Downloads: 60"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-68394200-1307091142_thumb.jpg" id='ipb-attach-img-2693-0-56849500-1330207787' style='width:250;height:123' class='attach' width="250" height="123" alt="Attached Image: Image14.jpg" /></a><br />
<span style='color: #000088'><em class='bbc'>Figure 1.0 - A Basic Biological Neuron.</em></span> <br />
<br />
</p><strong class='bbc'><br />
<span style='font-size: 18px;'>Biological Analogs</span></strong><br />
<br />
Neural  Nets were inspired by our own brains. Literally, some brain in  someone's head said, "I wonder how I work?" and then proceeded to create  a simple model of itself. Weird huh? The model of the standard neurode  is based on a simplified model of a human neuron invented over 50 years  ago. Take a look at Figure 1.0. As you can see, there are 3 main parts  to a neuron, they are:  <ul class='bbc'><li><em class='bbc'>Dendrite(s)........................</em>Responsible for collecting incoming signals.</li><li><em class='bbc'>Soma................................</em>Responsible for the main processing and summation of signals.</li><li><em class='bbc'>Axon.................................</em>Responsible for transmitting signals to other dendrites.</li></ul><span style='color: #000000'>The average human brain has about 100,000,000,000 or 10<sup class='bbc'>11</sup> neurons and each neuron has up to 10,000 connections </span>via the <em class='bbc'>dendrites</em>. The signals are passed via electro-chemical processes based on <em class='bbc'>NA</em> (sodium), <em class='bbc'>K</em> (potassium), and <em class='bbc'>CL</em>  (chloride) ions. Signals are transferred by accumulation and potential  differences caused by these ions, the chemistry is unimportant, but the  signals can be thought of simple electrical impulses that travel from <em class='bbc'>axon </em>to<em class='bbc'> dendrite</em>. The connections from one dendrite to axon are called <em class='bbc'>synapses</em> and these are the basic signal transfer points. <br />
<br />
So  how does a neuron work? Well, that doesn't have a simple answer, but  for our purposes the following explanation will suffice. The dendrites  collect the signals received from other neurons, then the soma performs a  summation of sorts and based on the result causes the axon to fire and  transmit the signal. The firing is contingent upon a number of factors,  but we can model it as an transfer function that takes the summed  inputs, processes them, and then creates an output if the properties of  the transfer function are met. In addition, the output is non-linear in  real neurons, that is, signals aren't digital, they are analog. In fact,  neurons are constantly receiving and sending signals and the real model  of them is frequency dependent and must be analyzed in the <em class='bbc'>S-domain</em>  (the frequency domain). The real transfer function of a simple  biological neuron has, in fact, been derived and it fills a number of  chalkboards up. <br />
<br />
Now that we have some idea of what neurons are  and what we are trying to model, let's digress for a moment and talk  about what we can use neural nets for in video games. <br />
<br />
<br />
<span style='font-size: 18px;'><strong class='bbc'>Applications to Games</strong></span><br />
<br />
Neural  nets seem to be the answer that we all are looking for. If we could  just give the characters in our games a little brains, imagine how cool a  game would be! Well, this is possible in a sense. Neural nets model the  structure of neurons in a crude way, but not the high level  functionality of reason and deduction, at least in the classical sense  of the words. It takes a bit of thought to come up with ways to apply  neural net technology to game AI, but once you get the hang of it, then  you can use it in conjunction with deterministic algorithms, fuzzy  logic, and genetic algorithms to create very robust thinking models for  your games. Without a doubt better than anything you can do with  hundreds of <em class='bbc'>if-then</em> statements or scripted logic. Neural nets can be used for such things as: <br />
<br />
<em class='bbc'>Environmental Scanning and Classification</em>  - A neural net can be feed with information that could be interpreted  as vision or auditory information. This information can then be used to  select an output response or teach the net. These responses can be  learned in real-time and updated to optimize the response. <br />
<br />
<em class='bbc'>Memory</em>  - A neural net can be used by game creatures as a form of memory. The  neural net can learn through experience a set of responses, then when a  new experience occurs, the net can respond with something that is the  best guess at what should be done. <br />
<br />
<em class='bbc'>Behavioral Control</em> -  The output of a neural net can be used to control the actions of a game  creature. The inputs can be various variables in the game engine. The  net can then control the behavior of the creature.  <br />
<br />
<em class='bbc'>Response Mapping</em> - Neural nets are really good at "association" which is the mapping of one space to another. Association comes in two flavors: <em class='bbc'>autoassociation</em> which is the mapping of an input with itself and <em class='bbc'>heterassociation</em>  which is the mapping of an input with something else. Response mapping  uses a neural net at the back end or output to create another layer of  indirection in the control or behavior of an object. Basically, we might  have a number of control variables, but we only have crisp responses  for a number of certain combinations that we can teach the net with.  However, using a neural net on the output, we can obtain other responses  that are in the same ballpark as our well defined ones. <br />
<br />
The  above examples may seem a little fuzzy, and they are. The point is that  neural nets are tools that we can use in whatever way we like. The key  is to use them in cool ways that make our <em class='bbc'>AI</em> programming simpler and make game creatures respond more intelligently. <br />
<br />
<br />
<span style='font-size: 18px;'><strong class='bbc'>Neural Nets 101</strong></span><br />
<br />
In  this section we're going to cover the basic terminology and concepts  used in neural net discussions. This isn't easy since neural nets are  really the work of a number of different disciplines, and therefore,  each discipline creates their own vocabulary. Alas, the vocabulary that  we will learn is a good intersection of all the well know vocabularies  and should suffice. In addition, neural network theory is replete with  research that is redundant, meaning that many people re-invent the  wheel. This has had the effect of creating a number of neural net  architectures that have names. I will try to keep things as generic as  possible, so that we don't get caught up in naming conventions. Later in  the article we will cover some nets that are distinct enough that we  will refer to them will their proper names. As you read don't be too  alarmed if you don't make the "connections" with all of the concepts,  just read them, we will cover most of them again in full context in the  remainder of the article. Let's begin... <span style='color: #000088'><em class='bbc'><br />
<br />
</em></span><p class='bbc_center'><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2692-0-56825900-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2692" title="Image15.jpg - Size: 20.61K, Downloads: 60"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-74835500-1307091132_thumb.jpg" id='ipb-attach-img-2692-0-56825900-1330207787' style='width:250;height:154' class='attach' width="250" height="154" alt="Attached Image: Image15.jpg" /></a><br />
<span style='color: #000088'><em class='bbc'>Figure 2.0 - A Single Neurode with n Inputs.</em></span><br />
</p><br />
Now  that we have seen the wetware version of a neuron, let's take a look at  the basic artificial neuron to base our discussions on. Figure 2.0 is a  graphic of a standard <em class='bbc'>"neurode"</em> or "<em class='bbc'>artificial neuron"</em>. As you can see, it has a number of inputs labeled <em class='bbc'>X<sub class='bbc'>1</sub> - X<sub class='bbc'>n</sub></em> and <em class='bbc'>B</em>. These inputs each have an associated weight <em class='bbc'>w<sub class='bbc'>1</sub> - w<sub class='bbc'>n</sub></em>, and <em class='bbc'>b</em> attached to them. In addition, there is a summing junction <em class='bbc'>Y</em> and a single output <em class='bbc'>y</em>. The output <em class='bbc'>y</em> of the neurode is based on a transfer or <em class='bbc'>"activation"</em> function which is a function of the net input to the neurode. The inputs come from the <em class='bbc'>X<sub class='bbc'>i'</sub>s</em> and from <em class='bbc'>B</em> which is a bias node. Think of <em class='bbc'>B</em> as a <em class='bbc'>"past history",</em> <em class='bbc'>"memory",</em> or <em class='bbc'>"inclination".</em> The basic operation of the neurode is as follows: the inputs <em class='bbc'>X<sub class='bbc'>i</sub></em> are each multiplied by their associated weights and summed. The output of the summing is referred to as the i<em class='bbc'>nput activation</em> <em class='bbc'>Y<sub class='bbc'>a</sub></em>.  The activation is then fed to the activation function <em class='bbc'>f<sub class='bbc'>a</sub>(x)</em> and the final output is <em class='bbc'>y.</em> The equations for this is: <br />
<br />
[indent] <span style='color: #000088'><em class='bbc'>Eq. 1.0</em></span> <span style='color: RED'> <em class='bbc'>                	<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n<br />
Y</em><sub class='bbc'>a</sub> = <em class='bbc'>B</em>*<em class='bbc'>b</em> + </span><span style='color: RED'><span style='font-family: Symbol'><span style='font-size: 10px;'>å</span></span></span><span style='color: RED'><span style='font-family: Symbol'> </span> <em class='bbc'>X</em><sub class='bbc'>i</sub> * <em class='bbc'>w</em><sub class='bbc'>i</sub> <br />
<em class='bbc'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i </em>=1<br />
 <br />
<br />
AND <br />
<br />
</span><span style='color: RED'><em class='bbc'>y</em> = <em class='bbc'>f<sub class='bbc'>a</sub>(Y<sub class='bbc'>a</sub>)</em> </span> <br />
[/indent]<br />
The various forms of <em class='bbc'>f<sub class='bbc'>a</sub>(x)</em> will be covered in a moment. <br />
<br />
Before we move on, we need to talk about the inputs <em class='bbc'>X<sub class='bbc'>i</sub></em>, the weights <em class='bbc'>w<sub class='bbc'>i</sub></em>, and their respective domains. In most cases, inputs consist of the positive and negative integers in the set ( -<span style='font-family: Symbol'>¥</span> , +inputs are <span style='font-family: Symbol'>¥</span> ).  However, many neural nets use simpler <em class='bbc'>bivalent</em> values (meaning that they have only two values).  The reason for using such a simple input scheme is that ultimately all <em class='bbc'>binary</em> as image or <em class='bbc'>bipolar</em>  and complex inputs are converted to pure binary or bipolar  representations anyway. In addition, many times we are trying to solve  computer problems such or voice recognition which lend themselves to  bivalent representations. Nevertheless, this is not etched in stone. In  any case, the values used in bivalent systems are primarily 0 and 1 in a  binary system or -1 and 1 in a bipolar system. Both systems are similar  except that bipolar representations turn out to be mathematically  better than binary ones. The weights <em class='bbc'>w<sub class='bbc'>i</sub></em> on each input are typically in the range bias ( -¥ , +¥ ). and are referred to as <em class='bbc'>excitatory</em>, and <em class='bbc'>inhibitory</em> for positive and negative values respectively. The extra input <em class='bbc'>B</em> which is called the is always 1.0 and is scaled or multiplied by <em class='bbc'>b</em>, that is, <em class='bbc'>b</em> is it's weight in a sense. This is illustrated in Eq.1.0 by the leading term. <br />
<br />
Continuing with our analysis, once the activation <em class='bbc'>Y<sub class='bbc'>a</sub></em> is found for a neurode then it is applied to the activation function and the output <em class='bbc'>y</em> can be computed. There are a number of activation functions and they have different uses. The basic activation functions <em class='bbc'>f<sub class='bbc'>a</sub>(x)</em> are: <br />
<br />
[indent]<table border="1" cellpadding="8" cellspacing="8"><tbody><tr><td><i>Step</i></td><td><i>Linear </i></td><td><i>Exponential</i></td></tr><tr><td><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2691-0-56804400-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2691" title="Image4.gif - Size: 1.47K, Downloads: 51"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-71537300-1307091111_thumb.gif" id='ipb-attach-img-2691-0-56804400-1330207787' style='width:160;height:120' class='attach' width="160" height="120" alt="Attached Image: Image4.gif" /></a></td><td><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2695-0-56872300-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2695" title="Image3.gif - Size: 1.43K, Downloads: 40"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-93570500-1307091215_thumb.gif" id='ipb-attach-img-2695-0-56872300-1330207787' style='width:160;height:120' class='attach' width="160" height="120" alt="Attached Image: Image3.gif" /></a></td><td><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2696-0-56895900-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2696" title="Image5.gif - Size: 1.51K, Downloads: 39"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-40172000-1307091266_thumb.gif" id='ipb-attach-img-2696-0-56895900-1330207787' style='width:160;height:120' class='attach' width="160" height="120" alt="Attached Image: Image5.gif" /></a></td></tr><tr><td><i>F<sub>s</sub>(x)</i> =1, if <i>x</i><font face="Symbol" size="2">³</font><font face="Symbol">q</font></td><td><i>F<sub>l</sub>(x)</i> = <i>x</i>,for all <i>x</i></td><td><i>F<sub>e</sub>(x)</i> =1/(1+e<sup>-</sup><font face="Symbol"><sup>s</sup></font><sup> <i>x</i></sup>)</td></tr></tbody></table><br />
[/indent] The equations for each are fairly simple, but each are derived to model or fit various properties. <br />
<br />
The <em class='bbc'>step</em>  function is used in a number of neural nets and models a neuron firing  when a critical input signal is reached. This is the purpose of the  factor <span style='font-family: Symbol'>q</span>, it models the critical input level or threshold that the neurode should fire at. The <em class='bbc'>linear</em> <em class='bbc'>activation</em>  function is used when we want the output of the neurode to more closely  follow the input activation. This kind of activation function would be  used in modeling <em class='bbc'>linear systems</em> such as basic motion with constant velocity. Finally, the <em class='bbc'>exponential</em> <em class='bbc'>activation function is</em> used to create a <em class='bbc'>non-linear response</em> which is the only possible way to create neural nets that have non-linear responses and model non-linear processes. The <em class='bbc'>exponential activation function</em> is key in advanced neural nets since the composition of linear and step activation functions will <em class='bbc'>always</em>  be linear or step, we will never be able to create a net that has  non-linear response, therefore, we need the exponential activation  function to address the non-linear problems that we want to solve with  neural nets. However, we are not locked into using the exponential  function. <em class='bbc'>Hyperbolic</em>, <em class='bbc'>logarithmic</em>, and <em class='bbc'>transcendental</em>  functions can be used as well depending on the desired properties of  the net. Finally, we can scale and shift all the functions if we need  to. <span style='color: #000088'><em class='bbc'><br />
<br />
</em></span><p class='bbc_center'><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2697-0-56918800-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2697" title="Image16.jpg - Size: 30.18K, Downloads: 48"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-35735200-1307091335_thumb.jpg" id='ipb-attach-img-2697-0-56918800-1330207787' style='width:250;height:148' class='attach' width="250" height="148" alt="Attached Image: Image16.jpg" /></a> <br />
<span style='color: #000088'><em class='bbc'>Figure 3.0 - A 4 Input, 3 Neurode, SingleLayer Neural Net.</em></span><span style='color: #000088'><em class='bbc'><br />
<br />
</em></span><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2699-0-56941000-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2699" title="Image17.jpg - Size: 40.06K, Downloads: 49"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-74375900-1307091491_thumb.jpg" id='ipb-attach-img-2699-0-56941000-1330207787' style='width:250;height:142' class='attach' width="250" height="142" alt="Attached Image: Image17.jpg" /></a><br />
<span style='color: #000088'><em class='bbc'>Figure 4.0 - A 2 Layer Neural Network.</em></span> <br />
</p><br />
As  you can imagine, a single neurode isn't going to do a lot for us, so we  need to take a group of them and create a layer of neurodes, this is  shown in Figure 3.0. The figure illustrates a single layer neural  network. The neural net in Figure 3.0 has a number of inputs and a  number of output nodes. By convention this is a single layer net since  the input layer is not counted unless it is the only layer in the  network. In this case, the input layer is also the output layer and  hence there is one layer. Figure 4.0 shows a two layer neural net.  Notice that the input layer is still not counted and the internal layer  is referred to as <em class='bbc'>"hidden".</em> The output layer is referred to as the <em class='bbc'>output</em> or <em class='bbc'>response</em>  layer. Theoretically, there is no limit to the number of layers a  neural net can have, however, it may be difficult to derive the  relationship of the various layers and come up with tractable training  methods. The best way to create multilayer neural nets is to make each  network one or two layers and then connect them as components or  functional blocks. <br />
<br />
All right, now let's talk about <em class='bbc'>temporal</em>  or time related topics. We all know that our brains are fairly slow  compared to a digital computer. In fact, our brains have cycle times in  the millisecond range whereas digital computers have cycle times in the  nanosecond and soon sub-nanosecond times. This means that signals take  time to travel from neuron to neuron. This is also modeled by artificial  neurons in the sense that we perform the computations layer by layer  and transmit the results sequentially. This helps to better model the  time lag involved in the signal transmission in biological systems such  as us. <br />
<br />
We are almost done with the preliminaries, let's talk  about some high level concepts and then finish up with a couple more  terms. The question that you should be asking is, "what the heck to  neural nets do?" This is a good question, and it's a hard one to answer  definitively. The question is more, "what do you want to try and make  them do?" They are basically mapping devices that help map one space to  another space. In essence, they are a type of memory. And like any  memory we can use some familiar terms to describe them. Neural nets have  both <em class='bbc'>STM</em> (<em class='bbc'>Short Term Memory</em>) and <em class='bbc'>LTM</em> (<em class='bbc'>Long Term Memory</em>).  STM is the ability for a neural net to remember something it just  learned, whereas, LTM is the ability of a neural net to remember  something it learned some time ago amongst its new learning. This leads  us to the concepts of <em class='bbc'>plasticity</em> or in other words how a neural  net deals with new information or training. Can a neural net learn more  information and still recall previously stored information correctly? If  so, does the neural net become unstable since it is holding so much  information that the data starts to overlapping or has common  intersections. This is referred to as <em class='bbc'>stability.</em> The bottom line  is we want a neural net to have a good LTM, a good STM, be plastic (in  most cases) and exhibit stability. Of course, some neural nets have no  analog to memory they are more for functional mapping, so these concepts  don't apply as is, but you get the idea. Now that we know about the  aforementioned concepts relating to memory, let's finish up by talking  some of the mathematical factors that help measure and understand these  properties. <br />
<br />
One of the main uses for neural nets are memories  that can process input that is either incomplete or noisy and return a  response. The response may be the input itself <em class='bbc'>(autoassociation) </em>or another output that is totally different from the input <em class='bbc'>(heteroassociation).</em> Also, the mapping may be from a <em class='bbc'>n</em>-dimensional space to a <em class='bbc'>m</em>-dimensional  space and non-linear to boot. The bottom line is that we want to some  how store information in the neural net so that inputs (perfect as well  as noisy) can be processed in parallel. This means that a neural net is a  kind of hyperdimensional memory unit since it can associate an input <em class='bbc'>n</em>-tuple with an output <em class='bbc'>m</em>-tupple where <em class='bbc'>m</em> can equal <em class='bbc'>n</em>, but doesn't have to. <br />
<br />
What neural nets do in essence is partition an <em class='bbc'>n</em>-dimensional  space into regions that uniquely map the input to the output or  classify the input into distinct classes like a funnel of sorts. Now, as  the number of input values (vectors) in the input data set increase  which we will refer to as <em class='bbc'>S</em>, it logically follows that the neural  net is going to have harder time separating the information. And as a  neural net is filled with information, the input values that are to be  recalled will overlap since the input space can no longer keep  everything partitioned in a finite number of dimensions. This overlap  results in <em class='bbc'>crosstalk,</em> meaning that some inputs are not as  distinct as they could be. This may or may not be desired. Although this  problem isn't a concern in all cases, it is a concern in associative  memory neural nets, so to illustrate the concept let's assume that we  are trying to associate <em class='bbc'>n</em>-tuple input vectors with some output set. The output set isn't as much of a concern to proper functioning as is the input set <em class='bbc'>S</em> is. <br />
<br />
If a set of inputs <em class='bbc'>S</em>  is straight binary then we are looking at sequences in the form  1101010...10110 let's say that our input bit vectors are only 3 bits  each, therefore the entire input space consist of the vectors: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>0</em></sub> = (0,0,0), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>1</em></sub> = (0,0,1), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>2</em></sub> = (0,1,0), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>3</em></sub> = (0,1,1), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>4</em></sub> = (1,0,0), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>5</em></sub> = (1,0,1), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>6</em></sub> = (1,1,0),  <br />
<br />
</span><span style='color: RED'><em class='bbc'>v</em><sub class='bbc'><em class='bbc'>7</em> </sub>= (1,1,1) </span> <br />
<br />
[/indent] To be more precise the <em class='bbc'>Basis</em> for this set of vectors is: <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>v</em> = (1,0,0) * <em class='bbc'>b</em><sub class='bbc'><em class='bbc'>2</em></sub> + (0,1,0) * <em class='bbc'>b</em><sub class='bbc'><em class='bbc'>1</em></sub> + (0,0,1) * <em class='bbc'>b</em><sub class='bbc'><em class='bbc'>0</em></sub>, where <em class='bbc'>b</em><sub class='bbc'><em class='bbc'>i</em></sub> can take on the values 0 or 1. </span> <br />
<br />
[/indent] For example if we let <em class='bbc'>b</em><sub class='bbc'><em class='bbc'>2</em></sub>=1, <em class='bbc'>b</em><sub class='bbc'><em class='bbc'>1</em></sub>=0, and <em class='bbc'>b</em><sub class='bbc'><em class='bbc'>0</em></sub>=1 then we get the vector: <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>v</em> = (1,0,0) * 1 + (0,1,0) * 0 + (0,0,1) * 1 = (1,0,0) + (0,0,0) + (0,0,1) = (1,0,1) which is <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>5</em></sub> in our possible input set. </span> <br />
<br />
[/indent] A <em class='bbc'>basis</em> is a special vector summation that describes a set of vectors in a space. So <em class='bbc'>v</em> describes all the vector in our space. Now to make a long story short, the more <em class='bbc'>orthogonal</em>  the vectors in the input set are the better they will distribute in a  neural net and the better they can be recalled. Orthogonality refers to  the independence of the vectors or in other words if two vector are  orthogonal then their dot product is 0, their projection onto one  another is 0, and they can't be written in terms of one another. In the  set <em class='bbc'>v</em> there are a lot of orthogonal vectors, but they come in small groups, for example <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>0</em></sub> is orthogonal to all the vectors, so we can always include it. But if we include <em class='bbc'>v</em><sub class='bbc'>1</sub> in our set <em class='bbc'>S</em> then the only other vectors that will fit and maintain orthogonality are <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>2</em></sub> and <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>4</em></sub> or the set: <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>v</em><sub class='bbc'><em class='bbc'>0</em></sub> = (0,0,0), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>1</em></sub> = (0,0,1), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>2</em></sub>= (0,1,0), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>4</em></sub> = (1,0,0) </span> <br />
<br />
[/indent] Why? Because <em class='bbc'>v</em><sub class='bbc'>i</sub> <span style='font-family: Symbol'>+</span> <em class='bbc'>v</em><sub class='bbc'>j</sub> for all <em class='bbc'>i,j</em>  from 0..3 is equal to 0. In other words, the dot product of all the  pairs of vectors in 0, so they must all be orthogonal. Therefore, this  set will do very well in a neural net as input vectors. However, the  set: <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>v</em><sub class='bbc'><em class='bbc'>6</em></sub> = (1,1,0), <em class='bbc'>v</em><sub class='bbc'><em class='bbc'>7</em></sub> = (1,1,1) </span> <br />
<br />
[/indent] will potentially do poorly as inputs since <em class='bbc'>v</em><sub class='bbc'>6</sub><span style='font-family: Symbol'>+</span><em class='bbc'>v</em><sub class='bbc'>7</sub>  is non-zero or in a binary system it is 1. The next question is, "can  we measure this orthogonality?" The answer is yes. In the binary vector  system there is a measure called hamming distance. It is used to measure  the n-dimensional distance between binary bit vectors. It is simply,  the number of bits that are different between two vectors. For example  the vectors: <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>v</em><sub class='bbc'>0</sub> = (0,0,0), <em class='bbc'>v</em><sub class='bbc'>1</sub> = (0,0,1) </span> <br />
<br />
[/indent] have a hamming distance of 1 while the vectors, <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>v</em><sub class='bbc'>2</sub> = (0,1,0), <em class='bbc'>v</em><sub class='bbc'>4</sub> = (1,0,0) </span> <br />
<br />
[/indent] have a hamming distance of 2.  <br />
<br />
We  can use hamming distance as the measure of orthogonality in binary bit  vector systems. And this can help us determine if our input vectors are  going to have a lot of overlap. Determining orthogonality with general  vector inputs is harder, but the concept is the same. That's all the  time we have for concepts and terminology, so let's jump right in and  see some actual neural nets that do something and hopefully by the end  of the article you will be able to use them in your game's AI. We are  going to cover neural nets used to perform logic functions, classify  inputs, and associate inputs with outputs. <span style='color: #000088'><em class='bbc'><br />
<br />
</em></span><p class='bbc_center'><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2700-0-56963100-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2700" title="Image18.jpg - Size: 15.97K, Downloads: 58"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-24969900-1307091546_thumb.jpg" id='ipb-attach-img-2700-0-56963100-1330207787' style='width:250;height:128' class='attach' width="250" height="128" alt="Attached Image: Image18.jpg" /></a><br />
<span style='color: #000088'><em class='bbc'>Figure 5.0 - The McCulloch-Pitts Neurode.</em></span> <br />
</p> <br />
<strong class='bbc'><br />
<span style='font-size: 18px;'>Pure Logic Mr. Spock</span></strong><br />
<br />
The first artificial neural networks were created in 1943 by <em class='bbc'>McCulloch</em> and <em class='bbc'>Pitts</em>. The neural networks were composed of a number of neurodes and were typically used to compute simple logic functions such as <em class='bbc'>AND</em>, <em class='bbc'>OR</em>, <em class='bbc'>XOR,</em>  and combinations of them. Figure 5.0 is a representation of a basic  McCulloch-Pitts neurode with 2 inputs. If you are an electrical engineer  then you will immediately see a close resemblance between  McCulloch-Pitts neurodes and transistors or <em class='bbc'>MOSFETs</em>. In any case, McCulloch-Pitts neurodes do <em class='bbc'>not</em> have biases and have the simple activation function <em class='bbc'>f</em><sub class='bbc'>mp</sub><em class='bbc'>(x)</em> equal to: <br />
<br />
[indent] <span style='color: #000088'><em class='bbc'>Eq. 5.0</em></span>  <span style='color: RED'><em class='bbc'><br />
<br />
f</em><sub class='bbc'>mp</sub><em class='bbc'>(x) = </em>1, if <em class='bbc'>x</em><span style='font-family: Symbol'><sup class='bbc'>3</sup>q</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0, if <em class='bbc'>x</em> < <span style='font-family: Symbol'>q</span> </span> <br />
<br />
[/indent] The <em class='bbc'>MP</em> (McCulloch-Pitts) neurode functions by summing the product of the inputs <em class='bbc'>X</em><sub class='bbc'>i</sub> and weights <em class='bbc'>w</em><sub class='bbc'>i</sub> and applying the result <em class='bbc'>Y</em><sub class='bbc'>a</sub> to the activation function <em class='bbc'>f</em><sub class='bbc'>mp</sub><em class='bbc'>(x).</em>  The early research of McCulloch-Pitts focused on creating complex  logical circuitry with the neurode models. In addition, one of the rules  of the neurode model is that is takes one time step for a signal to  travel from neurode to neurode. This helps model the biological nature  of neurons more closely. Let's take a look at some examples of MP neural  nets that implement basic logic functions. The logical <em class='bbc'>AND</em> function has the following truth table: <br />
<br />
<em class='bbc'><table border="1" cellpadding="2"><tbody><tr><td><i>X1</i></td><td><i>X2</i></td><td><i>Output</i></td></tr><tr><td>0</td><td>0</td><td>0</td></tr><tr><td>0</td><td>1</td><td>0</td></tr><tr><td>1</td><td>0</td><td>0</td></tr><tr><td>1</td><td>1</td><td>1</td></tr></tbody></table></em><span style='color: #000088'><em class='bbc'>Table 1.0 - Truth Table for Logical</em></span><span style='color: #000088'><em class='bbc'> AND. <br />
<br />
</em></span><p class='bbc_center'><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2702-0-56987000-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2702" title="Image19.jpg - Size: 35.55K, Downloads: 53"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-53388000-1307091708_thumb.jpg" id='ipb-attach-img-2702-0-56987000-1330207787' style='width:247;height:200' class='attach' width="247" height="200" alt="Attached Image: Image19.jpg" /></a><br />
<span style='color: #000088'><em class='bbc'>Figure 6.0 - Basic Logic Functions Implemented with McCulloch-Pitts Nets.</em></span> <br />
</p><br />
We can model this with a two input MP neural net with weights <em class='bbc'>w</em><sub class='bbc'>1</sub>=1, <em class='bbc'>w</em><sub class='bbc'>2</sub>=1, and <span style='font-family: Symbol'>q</span>  = 2. This neural net is shown in Figure 6.0a. As you can see, all input  combinations work correctly. For example, if we try inputs <em class='bbc'>X</em><sub class='bbc'>1</sub>=0, <em class='bbc'>Y</em><sub class='bbc'>1</sub>=1, then the activation will be: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>X</em><sub class='bbc'>1</sub>*<em class='bbc'>w</em><sub class='bbc'>1</sub> + <em class='bbc'>X</em><sub class='bbc'>2</sub>*<em class='bbc'>w</em><sub class='bbc'>2</sub> = (1)*(1) + (0)*(1) = 1.0<br />
<br />
</span> [/indent] If we apply 1.0 to the activation function <em class='bbc'>f</em><sub class='bbc'>mp</sub><em class='bbc'>(x)</em> then the result is 0 which is correct. As another example, if we try inputs <em class='bbc'>X</em><sub class='bbc'>1</sub>=1, <em class='bbc'>X</em><sub class='bbc'>2</sub>=1, then the activation will be: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>X</em><sub class='bbc'>1</sub>*<em class='bbc'>w</em><sub class='bbc'>1</sub> + <em class='bbc'>X</em><sub class='bbc'>2</sub>*<em class='bbc'>w</em><sub class='bbc'>2</sub> = (1)*(1) + (1)*(1) = 2.0<br />
<br />
</span> [/indent] If we input 2.0 to the activation function <em class='bbc'>f</em><sub class='bbc'>mp</sub><em class='bbc'>(x)</em>, then the result is 1.0 which is correct. The other cases will work also. The function of the <em class='bbc'>OR</em> is similar, but the threshold <span style='font-family: Symbol'>q</span> of is changed to 1.0 instead 2.0 as it is in the <em class='bbc'>AND</em>. You can try running through the truth table yourself to see the results.  <br />
<br />
The <em class='bbc'>XOR</em>  network is a little different because it really has 2 layers in a sense  because the results of the pre-processing are further processed in the  output neuron. This is a good example of why a neural net needs more  than one layer to solve certain problems. The <em class='bbc'>XOR</em> is a common problem in neural nets that is used to test a neural net's performance. In any case, <em class='bbc'>XOR</em>  is not linearly separable in a single layer, it must be broken down  into smaller problems and then the results added together. Let's take a  look at <em class='bbc'>XOR</em> as the final example of MP neural networks. The truth table for <em class='bbc'>XOR</em> is as follows: <span style='color: #000088'><em class='bbc'><br />
<br />
<span style='color: #000000'><em class='bbc'><table border="1" cellpadding="2"><tbody><tr><td><i>X1 </i></td><td><i>X2</i></td><td><i>Output</i></td></tr><tr><td>0</td><td>0</td><td>0</td></tr><tr><td>0</td><td>1</td><td>1</td></tr><tr><td>1</td><td>0</td><td>1</td></tr><tr><td>1</td><td>1</td><td>0</td></tr></tbody></table></em></span>Table 2.0 - Truth Table for Logical XOR.<br />
<br />
</em></span><p class='bbc_center'><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2703-0-57010200-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2703" title="Image20.jpg - Size: 25.31K, Downloads: 49"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-09740200-1307091824_thumb.jpg" id='ipb-attach-img-2703-0-57010200-1330207787' style='width:250;height:190' class='attach' width="250" height="190" alt="Attached Image: Image20.jpg" /></a><br />
<span style='color: #000088'><em class='bbc'>Figure 7.0 - Using the XOR Function to Illustrate Linear Separability.</em></span> <br />
</p><br />
<em class='bbc'>XOR</em> is only true when the inputs are different, this is a problem since both inputs map to the same output. <em class='bbc'>XOR</em>  is not linearly separable, this is shown in Figure 7.0. As you can see,  there is no way to separate the proper responses with a straight line.  The point is that we can separate the proper responses with 2 lines and  this is just what 2 layers do. The first layer pre-processes or solves  part of the problem and the remaining layer finishes up. Referring to  Figure 6.0c, we see that the weights are <em class='bbc'>w</em><sub class='bbc'>1</sub>=1, <em class='bbc'>w</em><sub class='bbc'>2</sub>=-1, <em class='bbc'>w</em><sub class='bbc'>3</sub>=1, <em class='bbc'>w</em><sub class='bbc'>4</sub>=-1, <em class='bbc'>w</em><sub class='bbc'>5</sub>=1, <em class='bbc'>w</em><sub class='bbc'>6</sub>=1. The network works as follows: layer one computes if <em class='bbc'>X</em><sub class='bbc'>1</sub> and <em class='bbc'>X</em><sub class='bbc'>2</sub>  are opposites in parallel, the results of either case (0,1) or (1,0)  are feed to layer two which sums these up and fires if either is true.  In essence we have created the logic function: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>z = ((X1 AND NOT X2) OR (NOT X1 AND X2))<br />
<br />
</em> </span> [/indent] If  you would like to experiment with the basic McCulloch Pitts neurode  Listing 1.0 is a complete 2 input, single neurode simulator that you can  experiment with. <br />
<br />
[indent] <span style='color: #000088'><em class='bbc'>Listing 1.0 - A McCulloch-Pitts Logic Neurode Simulator</em></span> 	<br />
<pre class='prettyprint'>// MCULLOCCH PITTS SIMULATOR<br />/////////////////////////////////////////////////////<br /><br />// INCLUDES<br />/////////////////////////////////////////////////////<br /><br />#include &lt;conio.h&gt;<br />#include &lt;stdlib.h&gt;<br />#include &lt;malloc.h&gt;<br />#include &lt;memory.h&gt;<br />#include &lt;string.h&gt;<br />#include &lt;stdarg.h&gt;<br />#include &lt;stdio.h&gt;<br />#include &lt;math.h&gt;<br />#include &lt;io.h&gt;<br />#include &lt;fcntl.h&gt;<br /><br />// MAIN<br />/////////////////////////////////////////////////////<br /><br />void main(void)<br />{<br />   float threshold, // this is the theta term used to threshold the summation <br />   w1,w2, // these hold the weights<br />   x1,x2, // inputs to the neurode <br />   y_in, // summed input activation<br />   y_out; // final output of neurode<br /><br />   printf("&#092;nMcCulloch-Pitts Single Neurode Simulator.&#092;n");<br />   printf("&#092;nPlease Enter Threshold?");<br />   scanf("%f",&threshold);<br /><br />   printf("&#092;nEnter value for weight w1?");<br />   scanf("%f",&w1);<br /><br />   printf("&#092;nEnter value for weight w2?");<br />   scanf("%f",&w2);<br /><br />   printf("&#092;n&#092;nBegining Simulation:");<br /><br />   // enter main event loop<br /><br />   while(1)<br />   {<br />  	printf("&#092;n&#092;nSimulation Parms: threshold=%f, W=(%f,%f)&#092;n",threshold,w1,w2);<br /><br />  	// request inputs from user<br />  	printf("&#092;nEnter input for X1?");<br />  	scanf("%f",&x1);<br /><br />  	printf("&#092;nEnter input for X2?");<br />  	scanf("%f",&x2);<br /><br />  	// compute activation<br />  	y_in = x1*w1 + x2*w2;<br /><br />  	// input result to activation function (simple binary step)<br />  	if(y_in &gt;= threshold)<br /> 		y_out = (float)1.0;<br />  	else<br /> 		y_out = (float)0.0;<br /><br />  	// print out result<br />  	printf("&#092;nNeurode Output is %f&#092;n",y_out);<br /><br />  	// try again<br />  	printf("&#092;nDo you wish to continue Y or N?");<br />  	char ans&#91;8&#93;;<br />  	scanf("%s",ans);<br /><br />  	if(toupper(ans&#91;0&#93;)!='Y')<br /> 		break;<br />   } // end while<br /><br />   printf("&#092;n&#092;nSimulation Complete.&#092;n");<br />} // end main</pre>[/indent] That  finishes up our discussion of the basic building block invented by  McCulloch and Pitts now let's move on to more contemporary neural nets  such as those used to classify input vectors. <br />
<span style='color: #000088'><em class='bbc'><br />
</em></span><p class='bbc_center'><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2704-0-57033000-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2704" title="Image21.jpg - Size: 18.72K, Downloads: 47"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-91884000-1307091907_thumb.jpg" id='ipb-attach-img-2704-0-57033000-1330207787' style='width:250;height:160' class='attach' width="250" height="160" alt="Attached Image: Image21.jpg" /></a><br />
<span style='color: #000088'><em class='bbc'>Figure 8.0 - The Basic Neural Net Model Used for Discussion.</em></span> <br />
</p> <br />
<strong class='bbc'><br />
<span style='font-size: 18px;'>Classification and "Image" Recognition</span></strong><br />
<br />
At  this point we are ready to start looking at real neural nets that have  some girth to them! To segue into the following discussions on <em class='bbc'>Hebbian</em>, and <em class='bbc'>Hopfield</em>  neural nets, we are going to analyze a generic neural net structure  that will illustrate a number of concepts such as linear separability,  bipolar representations, and the analog that neural nets have with  memories. Let's begin with taking a look at Figure 8.0 which is the  basic neural net model we are going to use. As you can see, it is a  single node net with 3 inputs including the bias, and a single output.  We are going to see if we can use this network to solve the logical <em class='bbc'>AND</em> function that we solved so easily with McCulloch-Pitts neurodes. <br />
<br />
Let's  start by first using bipolar representations, so all 0's are replaced  with -1's and 1's are left alone. The truth table for logical <em class='bbc'>AND</em> using bipolar inputs and outputs is shown below: <span style='color: #000088'><em class='bbc'><br />
<br />
<span style='color: #000000'><em class='bbc'><table border="1" cellpadding="2"><tbody><tr><td><i>X1</i></td><td><i>X2</i></td><td><i>Output</i></td></tr><tr><td>-1</td><td>-1</td><td>-1</td></tr><tr><td>-1</td><td>1</td><td>-1</td></tr><tr><td>1</td><td>-1</td><td>-1</td></tr><tr><td>1</td><td>1</td><td>1</td></tr></tbody></table></em></span>Table 3.0 - Truth Table for Logical AND in Bipolar Format.</em></span><br />
<br />
And here is the activation function <em class='bbc'>f</em><sub class='bbc'>c</sub><em class='bbc'>(x)</em> that we will use: <br />
<br />
[indent] <span style='color: #000088'><em class='bbc'>Eq. 6.0</em></span>  <br />
<br />
<span style='color: RED'><em class='bbc'>f<sub class='bbc'>c</sub></em><em class='bbc'>(x)</em> <em class='bbc'>=</em> 1, if <em class='bbc'>x</em> <sup class='bbc'>3</sup> <span style='font-family: Symbol'>q</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-1, if <em class='bbc'>x</em> < <span style='font-family: Symbol'>q</span> </span> <br />
<br />
[/indent] Notice  that the function is step with bipolar outputs. Before we continue, let  me place a seed in your mind; the bias and threshold end up doing the  same thing, they give us another degree of freedom in our neurons that  make the neurons respond in ways that can't be achieved without them.  You will see this shortly. <br />
<br />
The single neurode net in Figure 8.0  is going to perform a classification for us. It is going to tell us if  our input is in one class or another. For example, is this image a tree  or <em class='bbc'><em class='bbc'>not</em></em> a tree. Or in our case is this input (which just happens to be the logic for an <em class='bbc'>AND</em>)  in the +1 or -1 class? This is the basis of most neural nets and the  reason I was belaboring linear separability. We need to come up with a  linear partitioning of space that maps our inputs and outputs so that  there is a solid delineation of space that separates them. Thus, we need  to come up with the correct weights and a bias that will do this for  us. But how do we do this? Do we just use trial and error or is there a  methodology? The answer is that there are a number of training methods  to teach a neural net. These training methods work on various  mathematical premises and can be proven, but for now, we're just going  to pull some values out of the hat that work. These exercises will lead  us into the learning algorithms and more complex nets that follow. <br />
<br />
All right, we are trying to finds weights <em class='bbc'>w</em><sub class='bbc'>i</sub> and bias <em class='bbc'>b</em> that give use the correct result when the various inputs are feed to our network with the given activation function <em class='bbc'>f</em><sub class='bbc'>c</sub><em class='bbc'>(x).</em>  Let's write down the activation summation of our neurode and see if we  can infer any relationship between the weights and the inputs that might  help us. Given the inputs <em class='bbc'>X</em><sub class='bbc'>1</sub> and <em class='bbc'>X</em><sub class='bbc'>2</sub> with weights <em class='bbc'>w</em><sub class='bbc'>1</sub> and <em class='bbc'>w</em><sub class='bbc'>2</sub> along with <em class='bbc'>B</em>=1 and bias <em class='bbc'>b</em>, we have the following formula: <br />
<br />
[indent] <span style='color: #000088'><em class='bbc'>Eq. 7.0</em></span>  <span style='color: RED'><em class='bbc'><br />
<br />
X</em><sub class='bbc'>1</sub>*<em class='bbc'>w</em><sub class='bbc'>1</sub> + <em class='bbc'>X</em><sub class='bbc'>2</sub>*<em class='bbc'>w</em><sub class='bbc'>2</sub> + <em class='bbc'>B</em>*<em class='bbc'>b</em>=<span style='font-family: Symbol'>q</span> </span> <br />
<br />
[/indent] Since <em class='bbc'>B</em> is always equal to 1.0 the equation simplifies to: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>X</em><sub class='bbc'>1</sub>*<em class='bbc'>w</em><sub class='bbc'>1</sub> + <em class='bbc'>X</em><sub class='bbc'>2</sub>*<em class='bbc'>w</em><sub class='bbc'>2</sub> + <em class='bbc'>b</em>=<span style='font-family: Symbol'>q</span> <br />
<br />
. <br />
<br />
. <br />
<br />
</span><span style='color: RED'><em class='bbc'>X</em><sub class='bbc'>2</sub> = -<em class='bbc'>X</em><sub class='bbc'>1</sub>*<em class='bbc'>w</em><sub class='bbc'>1</sub>/<em class='bbc'>w</em><sub class='bbc'>2</sub> + (<span style='font-family: Symbol'>q</span> -<em class='bbc'>b</em>)/<em class='bbc'>w</em><sub class='bbc'>2 </sub>(solving in terms of <em class='bbc'>X</em><sub class='bbc'>2</sub>) </span> <br />
<br />
[/indent]<p class='bbc_center'><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2705-0-57055400-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2705" title="Image22.jpg - Size: 28.71K, Downloads: 47"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-41135400-1307092076_thumb.jpg" id='ipb-attach-img-2705-0-57055400-1330207787' style='width:250;height:161' class='attach' width="250" height="161" alt="Attached Image: Image22.jpg" /></a><br />
<span style='color: #000088'><em class='bbc'>Figure 9.0 - Mathematical Decision Boundaries Generated by Weights, Bias, and <span style='font-family: Symbol'>q</span></em></span> <br />
</p><br />
What is this entity? It's a line! And if the left hand side is greater than or equal to <span style='font-family: Symbol'>q</span>, that is, (<em class='bbc'>X</em><sub class='bbc'>1</sub>*<em class='bbc'>w</em><sub class='bbc'>1</sub> + <em class='bbc'>X</em><sub class='bbc'>2</sub>*<em class='bbc'>w</em><sub class='bbc'>2</sub> + <em class='bbc'>b</em>)  then the neurode will fire and output 1, otherwise the neurode will  output -1. So the line is a decision boundary. Figure 9.0a illustrates  this. Referring to the figure, you can see that the slope of the line is  <em class='bbc'>-w</em><sub class='bbc'><em class='bbc'>1</em></sub><em class='bbc'>/w</em><sub class='bbc'><em class='bbc'>2</em></sub> and the <em class='bbc'>X</em><sub class='bbc'><em class='bbc'>2</em></sub> intercept is (<span style='font-family: Symbol'>q</span> -<em class='bbc'>b</em>)/<em class='bbc'>w</em><sub class='bbc'>2</sub>. Now can you see why we can get rid of <span style='font-family: Symbol'>q</span>? It is part of a constant and we can always scale b to take up any loss, so we will assume that <span style='font-family: Symbol'>q</span> = 0, and the resulting equation is: <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>X</em><sub class='bbc'>2</sub> = -<em class='bbc'>X</em><sub class='bbc'>1</sub>*<em class='bbc'>w</em><sub class='bbc'>1</sub><em class='bbc'>/w</em><sub class='bbc'>2</sub> - <em class='bbc'>b/w</em></span><span style='color: #FF0000'><sub class='bbc'>2</sub></span><br />
<br />
[/indent] What we want to find are weights <em class='bbc'>w</em><sub class='bbc'><em class='bbc'>1</em></sub> and <em class='bbc'>w</em><sub class='bbc'>2</sub> and bias <em class='bbc'>b</em>  so that it separates our outputs or classifies them into singular  partitions without overlap. This is the key to linear separability.  Figure 9.0b shows a number of decision boundaries that will suffice, so  we can pick any of them. Let's pick the simplest values which would be: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>w</em><sub class='bbc'>1</sub> = <em class='bbc'>w</em><sub class='bbc'>2</sub> = 1 <br />
<br />
</span><span style='color: RED'><em class='bbc'>b</em> = -1 </span> <br />
<br />
[/indent] With these values our decision boundary becomes: <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>X</em><sub class='bbc'>2</sub> = -<em class='bbc'>X</em><sub class='bbc'>1</sub>*<em class='bbc'>w</em><sub class='bbc'>1</sub><em class='bbc'>/w</em><sub class='bbc'>2</sub> - <em class='bbc'>b/w</em><sub class='bbc'>2</sub> -> <em class='bbc'>X</em><sub class='bbc'>2</sub> = -1*<em class='bbc'>X</em><sub class='bbc'>1</sub> + 1 </span> <br />
<br />
[/indent] The slope is -1 and the <em class='bbc'>X</em><sub class='bbc'>2</sub> intercept is 1. If we plug the input vectors for the logical <em class='bbc'>AND</em> into this equation and use the <em class='bbc'>f</em><sub class='bbc'>c</sub><em class='bbc'>(x)</em> activation function then we will get the correct outputs. For example if, <em class='bbc'>X</em><sub class='bbc'>2</sub> + <em class='bbc'>X</em><sub class='bbc'>1</sub>-1 >0 then fire the neurode, else output -1. Let's try it with our <em class='bbc'>AND</em> inputs and see what we come up with: <span style='color: #000088'><em class='bbc'><br />
<br />
<em class='bbc'><table border="1" cellpadding="2"><tbody><tr><td><i>Input </i></td><td><i>X1</i></td><td><i>X2</i></td><td><i>Output (X2+X1-1)</i></td></tr><tr><td>&nbsp;</td><td>-1</td><td>-1</td><td>(-1) +( -1) -1 = 3 < 0 don't fire, output -1</td></tr><tr><td>&nbsp;</td><td>-1</td><td>1</td><td>(-1) + (1) -1 = -1< 0 don't fire, output -1</td></tr><tr><td>&nbsp;</td><td>1</td><td>-1</td><td>(1) + (-1) -1 = -2 < 0 don't fire, output -1</td></tr><tr><td>&nbsp;</td><td>1</td><td>1</td><td>(1) + (1)-1 = 1 > 0 fire, output 1</td></tr></tbody></table></em>Table 4.0 - Truth Table for Bipolar AND with decision boundary.</em></span><br />
<br />
As  you can see, the neural network with the proper weights and bias solves  the problem perfectly. Moreover, there are a whole family of weights  that will do just as well (sliding the decision boundary in a direction  perpendicular to itself). However, there is an important point here.  Without the bias or threshold, only lines through the origin would be  possible since the <em class='bbc'>X</em><sub class='bbc'>2</sub> intercept would have to be 0.  This is very important and the basis for using a bias or threshold, so  this example has proven to be an important one since it has flushed this  fact out. So, are we closer to seeing how to algorithmically find  weights? Yes, we now have a geometrical analogy and this is the  beginning of finding an algorithm. <br />
<br />
<br />
<span style='font-size: 18px;'><strong class='bbc'>The Ebb of Hebbian</strong></span><br />
<br />
Now  we are ready to see the first learning algorithm and its application to  a neural net. One of the simplest learning algorithms was invented by <em class='bbc'>Donald Hebb</em>  and it is based on using the input vectors to modify the weights in a  way so that the weight create the best possible linear separation of the  inputs and outputs. Alas, the algorithm works just OK. Actually, for  inputs that are orthogonal it is perfect, but for non-orthogonal inputs,  the algorithm falls apart. Even though, the algorithm doesn't result in  correct weight for all inputs, it is the basis of most learning  algorithms, so we will start here. <br />
<br />
Before we see the algorithm,  remember that it is for a single neurode, single layer neural net. You  can of course, place a number of neurodes in the layer, but they will  all work in parallel and can be taught in parallel. Are you starting to  see the massive parallization that neural nets exhibit? Instead of using  a single weight vector, a multi-neurode net uses a weight matrix.  Anyway, the algorithm is simple, it goes something like this: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>Given:</em> <br />
<ul class='bbc'><li>Inputs vectors are in bipolar form <em class='bbc'>I</em> = (-1,1,0,...-1,1) and contain k elements. 	</li><li>There are <em class='bbc'>n</em> input vectors and we will refer to the set as <em class='bbc'>I</em> and the <em class='bbc'>j</em>th element as <em class='bbc'>I</em><sub class='bbc'>j</sub><em class='bbc'>.</em> 	</li><li>Outputs will be referred to as <em class='bbc'>y</em><sub class='bbc'>j</sub> and there are k of them, one for each input <em class='bbc'>I</em><sub class='bbc'>j</sub> 	</li><li>The weights <em class='bbc'>w</em><sub class='bbc'>1</sub><em class='bbc'>-w</em><sub class='bbc'>k</sub> are contained in a single vector <em class='bbc'>w</em> = (<em class='bbc'>w</em><sub class='bbc'>1</sub>, <em class='bbc'>w</em><sub class='bbc'>2</sub>, ... <em class='bbc'>w</em><sub class='bbc'>k</sub>).</li></ul> </span> [/indent] <em class='bbc'>Step 1.</em> Initialize all your weights to 0, and let them be contained in a vector <em class='bbc'>w</em> that has <em class='bbc'>n</em> entries. Also initialize the bias b to 0. <br />
<br />
<em class='bbc'>Step 2.</em> For <em class='bbc'>j</em> = 1 to <em class='bbc'>n</em> do <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>b</em> = <em class='bbc'>b</em> + <em class='bbc'>y</em><sub class='bbc'><em class='bbc'>j</em></sub> (where y is the desired output) <br />
<br />
</span><span style='color: RED'><em class='bbc'>w</em> = <em class='bbc'>w</em> + <em class='bbc'>I</em><sub class='bbc'><em class='bbc'>j</em></sub> * <em class='bbc'>y</em><sub class='bbc'><em class='bbc'>j</em></sub> (remember this is a vector operation) </span> <br />
<br />
[/indent] end do <br />
<br />
The algorithm is nothing more than an <em class='bbc'>"accumulator"</em>  of sorts. Shifting, the decision boundary based on the changes in the  input and output. The only problem is that it sometimes can't move the  boundary fast enough (or at all) and <em class='bbc'>"learning"</em> doesn't take place. <br />
<br />
So how do we use <em class='bbc'>Hebbian</em>  learning? The answer is, the same as the previous network except that  now we have an algorithmic method teach the net with, thus we refer to  the net as a <em class='bbc'>Hebb </em>or <em class='bbc'>Hebbian Net</em>. As an example, let's take our trusty logical <em class='bbc'>AND</em>  function and see if the algorithm can find the proper weights and bias  to solve the problem. The following summation is equivalent to running  the algorithm: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>w</em> = [<em class='bbc'>I</em><sub class='bbc'>1</sub>*<em class='bbc'>y</em><sub class='bbc'>1</sub>] + [<em class='bbc'>I</em><sub class='bbc'>2</sub>*<em class='bbc'>y</em><sub class='bbc'>2</sub>] + [<em class='bbc'>I</em><sub class='bbc'>3</sub>*<em class='bbc'>y</em><sub class='bbc'>3</sub>] + [<em class='bbc'>I</em><sub class='bbc'>4</sub>*<em class='bbc'>y</em><sub class='bbc'>4</sub>] = [(-1, -1)*(-1)] + [(-1, 1)*(-1)] + [( 1, -1)*(-1)] + [(1, 1)*(1)] = (2,2)  <br />
<br />
</span><span style='color: RED'><em class='bbc'>b</em> = <em class='bbc'>y</em><sub class='bbc'>1</sub> + <em class='bbc'>y</em><sub class='bbc'>2</sub> + <em class='bbc'>y</em><sub class='bbc'>3</sub> + <em class='bbc'>y</em><sub class='bbc'>4</sub> = (-1) + (-1) + (-1) + (1) = -2 </span> <br />
<br />
[/indent] Therefore, <em class='bbc'>w</em><sub class='bbc'>1</sub>=2, <em class='bbc'>w</em><sub class='bbc'>2</sub>=2, and <em class='bbc'>b</em>=-2. These are simply scaled versions of the values <em class='bbc'>w</em><sub class='bbc'>1</sub>=1, <em class='bbc'>w</em><sub class='bbc'>2</sub>=1, <em class='bbc'>b</em>=-1  that we derived geometrically in the previous section. Killer huh! With  this simple learning algorithm we can train a neural net (consisting of  a single neurode) to respond to a set of inputs and either classify the  input as true or false, 1 or -1. Now if we were to array these neurodes  together to create a network of neurodes then instead of simple  classifying the inputs as on or off, we can associate patterns with the  inputs. This is one of the foundations for the next network neural net  structure; the <em class='bbc'>Hopfield</em> net. One more thing, the activation  function used for a Hebb Net is a step with a threshold of 0.0 and  bipolar outputs 1 and -1. <br />
<br />
To get a feel for Hebbian learning and  how to implement an actual Hebb Net, Listing 2.0 contains a complete  Hebbian Neural Net Simulator. You can create networks with up to 16  inputs and 16 neurodes (outputs). The program is self explanatory, but  there are a couple of interesting properties: you can select 1 of 3  activation functions, and you can input any kind of data you wish.  Normally, we would stick to the Step activation function and  inputs/outputs would be binary or bipolar. However, in the light of  discovery, maybe you will find something interesting with these added  degrees of freedom. However, I suggest that you begin with the step  function and all bipolar inputs and outputs. <br />
<br />
[indent] <span style='color: #000088'><em class='bbc'>Listing 2.0 - A Hebb Net Simulator (in neuralnet.zip).</em></span> [/indent] <br />
<br />
<span style='font-size: 18px;'><strong class='bbc'>Playing the Hopfield</strong></span><span style='color: #000088'><em class='bbc'><br />
<br />
</em></span><p class='bbc_center'><a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2706-0-57078500-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2706" title="Image23.jpg - Size: 34.18K, Downloads: 43"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-01939400-1307092359_thumb.jpg" id='ipb-attach-img-2706-0-57078500-1330207787' style='width:250;height:177' class='attach' width="250" height="177" alt="Attached Image: Image23.jpg" /></a><br />
<span style='color: #000088'><em class='bbc'>Figure 10.0 - A 4 Node Hopfield Autoassociative Neural Net.</em></span> <br />
</p><br />
John  Hopfield is a physicist that likes to play with neural nets (which is  good for us). He came up with a simple (in structure at least), but  effective neural network called the <em class='bbc'>Hopfield Net.</em> It is used for autoassociation, you input a vector <em class='bbc'>x</em> and you get <em class='bbc'>x</em>  back (hopefully). A Hopfield net is shown in Figure 10.0. It is a  single layer network with a number of neurodes equal to the number of  inputs <em class='bbc'>X</em><sub class='bbc'>i</sub>. The network is fully connected meaning that  every neurode is connected to every other neurode and the inputs are  also the outputs. This should strike you as weird since there is <em class='bbc'>feedback</em>.  Feedback is one of the key features of the Hopfield net and this  feedback is the basis for the convergence to the correct result.  <br />
<br />
The Hopfield network is an <em class='bbc'>iterative autoassociative memory.</em>  This means that is may take one or more cycles to return the correct  result (if at all). Let me clarify; the Hopfield network takes an input  and then feeds it back, the resulting output may or may not be the  desired input. This feedback cycle may occur a number of times before  the input vector is returned. Hence, a Hopfield network functional  sequence is: first we determine the weights based on our input vectors  that we want to autoassociate, then we input a vector and see what comes  out of the activations. If the result is the same as our original input  then we are done, if not, then we take the result vector and feed it  back through the network. Now let's take a look at the weight matrix and  learning algorithm used for Hopfield nets. <br />
<br />
The learning  algorithm for Hopfield nets is based on the Hebbian rule and is simply a  summation of products. However, since the Hopfield network has a number  of input neurons the weights are no longer a single array or vector,  but a collection of vectors which are most compactly contained in a  single matrix. Thus the weight matrix <em class='bbc'>W</em> for a Hopfield net is created based on this equation: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>Given:</em> <br />
<ul class='bbc'><li>Inputs vectors are in bipolar form <em class='bbc'>I</em> = (-1,1,,...-1,1) and contain <em class='bbc'>k</em> elements. 	</li><li>There are <em class='bbc'>n</em> input vectors and we will refer to the set as <em class='bbc'>I</em> and the <em class='bbc'>j</em>th element as <em class='bbc'>I</em><sub class='bbc'>j</sub>. 	</li><li>Outputs will be referred to as <em class='bbc'>y</em><sub class='bbc'>j</sub> and there are <em class='bbc'>k</em> of them, one for each input <em class='bbc'>I</em><sub class='bbc'>j</sub>. 	</li><li>The weight matrix <em class='bbc'>W</em> is square and has dimension <em class='bbc'>k</em>x<em class='bbc'>k</em> since there are <em class='bbc'>k</em> inputs.</li></ul> <span style='color: #000088'><em class='bbc'>Eq. 8.0</em></span> <br />
<br />
</span><span style='color: RED'><em class='bbc'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;k</em> <br />
<em class='bbc'>W</em> <sub class='bbc'>(kxk)</sub> = </span><span style='color: RED'><span style='font-family: Symbol'>å</span></span><span style='color: RED'> <em class='bbc'>I</em><sub class='bbc'>i</sub><sup class='bbc'>t</sup> x <em class='bbc'>I</em><sub class='bbc'>i</sub> <br />
<em class='bbc'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i</em> = 1<br />
</span> <br />
<br />
[/indent] note: each outer product will have dimension <em class='bbc'>k</em> x <em class='bbc'>k</em>, since we are multiplying a column vector and a row vector. <br />
<br />
and, <em class='bbc'>W</em><sub class='bbc'>ii</sub> = 0, for all<em class='bbc'> i</em>. <br />
<br />
Notice that there are no bias terms and the main diagonal of <em class='bbc'>W</em> must be all zero's. The weight matrix is simply the sum of matrices generated by multiplying the transpose <em class='bbc'>I</em><sub class='bbc'>i</sub><sup class='bbc'>t</sup> x <em class='bbc'>I</em><sub class='bbc'>i </sub>for all <em class='bbc'>i</em> from 1 to <em class='bbc'>n</em>.  This is almost identical to the Hebbian algorithm for a single neurode  except that instead of multiplying the input by the output, the input is  multiplied by itself, which is equivalent to the output in the case of  autoassociation. Finally, the activation function <em class='bbc'>f</em><sub class='bbc'>h</sub><em class='bbc'>(x) </em>is shown below: <br />
<br />
[indent] <span style='color: #000088'><em class='bbc'>Eq. 9.0</em></span>  <br />
<br />
<span style='color: RED'><em class='bbc'>f</em><sub class='bbc'>h</sub><em class='bbc'>(x)</em> <em class='bbc'>= </em>1, if <em class='bbc'>x</em> <sup class='bbc'><span style='font-family: Symbol'>3</span></sup> 0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0, if <em class='bbc'>x</em> < 0 </span> <br />
<br />
[/indent] <em class='bbc'>f</em><sub class='bbc'>h</sub><em class='bbc'>(x) </em>it  is a step function with a binary output. This means that the inputs  must be binary, but we already said that inputs are bipolar? Well, they  are, and they aren't. When the weight matrix is generated we convert all  input vectors to bipolar, but for normal operation we use the binary  version of the inputs and the output of the Hopfield net will also be  binary. This convention is not necessary, but makes the network  discussion a little simpler. Anyway, let's move on to an example. Say we  want to create a four node Hopfield net and we want it to recall these  vectors:  <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>I</em><sub class='bbc'>1</sub>=(0,0,1,0), <em class='bbc'>I</em><sub class='bbc'>2</sub>=(1,0,0,0), <em class='bbc'>I</em><sub class='bbc'>3</sub>=(0,1,0,1) Note: they are all orthogonal. </span> <br />
<br />
[/indent] Converting to bipolar *, we have: <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>I</em><sub class='bbc'>1</sub><sup class='bbc'>*</sup> = (-1,-1,1,-1) , <em class='bbc'>I</em><sub class='bbc'>2</sub><sup class='bbc'>*</sup> = (1,-1,-1,-1) , <em class='bbc'>I</em><sub class='bbc'>3</sub><sup class='bbc'>*</sup> = (-1,1,-1,1) </span> <br />
<br />
[/indent] Now we need to compute <em class='bbc'>W</em><sub class='bbc'>1</sub>, <em class='bbc'>W</em><sub class='bbc'>2</sub>, <em class='bbc'>W</em><sub class='bbc'>3</sub>, where <em class='bbc'>W</em><sub class='bbc'>i</sub> is the product of the transpose of each input with itself. <br />
<br />
<a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2707-0-57102800-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2707" title="fig1.png - Size: 7.58K, Downloads: 42"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-72426400-1307092909_thumb.png" id='ipb-attach-img-2707-0-57102800-1330207787' style='width:130;height:200' class='attach' width="130" height="200" alt="Attached Image: fig1.png" /></a> <br />
<br />
Then we add <em class='bbc'>W</em><sub class='bbc'>1</sub> + <em class='bbc'>W</em><sub class='bbc'>2</sub> + <em class='bbc'>W</em><sub class='bbc'>3</sub> resulting in: <br />
<br />
<a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2708-0-57125600-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2708" title="fig2.png - Size: 2.1K, Downloads: 35"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-05593400-1307092910_thumb.png" id='ipb-attach-img-2708-0-57125600-1330207787' style='width:120;height:157' class='attach' width="120" height="157" alt="Attached Image: fig2.png" /></a><br />
<br />
Zeroing out the main diagonal gives us the final weight matrix: <br />
<br />
<a class='resized_img' rel='lightbox[79247f279ff54f958f6a2e40c451f740]' id='ipb-attach-url-2709-0-57148700-1330207787' href="http://www.gamedev.net/index.php?app=core&module=attach&section=attach&attach_rel_module=ccs&attach_id=2709" title="fig3.png - Size: 1.66K, Downloads: 40"><img src="http://public.gamedev.net/uploads/monthly_06_2011/ccs-8549-0-35889200-1307092910_thumb.png" id='ipb-attach-img-2709-0-57148700-1330207787' style='width:120;height:157' class='attach' width="120" height="157" alt="Attached Image: fig3.png" /></a><br />
<br />
That's  it, now we are ready to rock. Let's input our original vectors and see  the results. To do this we simply have to matrix multiple the input by  the matrix and then process each output value with our activation  function <em class='bbc'>f</em><sub class='bbc'>h</sub><em class='bbc'>(x).</em> Here are the results: <br />
<br />
[indent] <span style='color: RED'> <em class='bbc'>I</em><sub class='bbc'>1</sub><em class='bbc'> x W</em> = (-1,-1,0,-1) and <em class='bbc'>f</em><sub class='bbc'>h</sub><em class='bbc'>(</em>(-1,-1,0,-1)<em class='bbc'>)</em> = (0,0,1,0) <br />
<br />
<em class='bbc'>I</em><sub class='bbc'>2</sub><em class='bbc'> x W</em> = (0,-1,-1,-1) and <em class='bbc'>f</em><sub class='bbc'>h</sub><em class='bbc'>(</em>(0,-1,-1,-1)<em class='bbc'>) = </em>(1,0,0,0) <br />
<br />
</span><span style='color: RED'><em class='bbc'>I</em><sub class='bbc'>3</sub><em class='bbc'> x W</em> = (-2,3,-2,3) and <em class='bbc'>f</em><sub class='bbc'>h</sub><em class='bbc'>(</em>(-2,3,-2,3)<em class='bbc'>) = </em>(0,1,0,1) </span> <br />
<br />
[/indent] The  inputs were perfectly recalled, and they should be since they were all  orthogonal. As a final example, let's assume that our input (vision,  auditory etc.) is a little noisy and the input has a single error in it.  Let's take <em class='bbc'>I</em><sub class='bbc'>3</sub> = (0,1,0,1) and add some noise to <em class='bbc'>I</em><sub class='bbc'>3</sub> resulting in <em class='bbc'>I</em><sub class='bbc'>3</sub><sup class='bbc'>noise</sup> = (0,1,1,1). Now let's see what happens if we input this noisy vector to the Hopfield net: <br />
<br />
[indent]  <span style='color: RED'><em class='bbc'>I</em><sub class='bbc'>3</sub><sup class='bbc'>noise</sup> x <em class='bbc'>W</em> = (-3, 2, -2, 2) and <em class='bbc'>f</em><sub class='bbc'>h</sub><em class='bbc'>(</em>(-3,2,-2, 2)<em class='bbc'>) = </em>(0,1,0,1) </span> <br />
<br />
[/indent] Amazingly  enough, the original vector is recalled. This is very cool. So we might  have a memory that is filled with bit patterns that look like trees,  (oaks, weeping willow, spruce, redwood etc.) then if we input another  tree that is similar to say a weeping willow, but hasn't been entered  into the net, our net will (hopefully) output a weeping willow  indicating that this is what it "thinks" it looks like. This is one of  the strengths of associative memories, we don't have to teach it every  possible input, but just enough to give it a good idea. Then inputs that  are <em class='bbc'>"close"</em> will usually converge to an actual trained input.  This is the basis for image, and voice recognition systems. Don't ask me  where the heck the "tree" analogy came from. Anyway, to complete our  study of neural nets, I have included a final Hopfield autoassociative  simulator that allows you to create nets with up to 16 neurodes. It is  similar to the Hebb Net, but you must use a step activation function and  your inputs exemplars must be in bipolar while training and binary  while associating (running). Listing 3.0 contains the code for the  simulator. <br />
<br />
[indent] <span style='color: #000088'><em class='bbc'>Listing 3.0 - A Hopfiled Autoassociative Memory Simulator (in neuralnet.zip).</em></span> [/indent] <br />
<br />
<span style='font-size: 18px;'><strong class='bbc'>Brain Dead...</strong></span><br />
<br />
Well that's all we have time for. I was hoping to get to the <em class='bbc'>Perceptron</em>  network, but oh well. I hope that you have an idea of what neural nets  are and how to create some working computer programs to model them. We  covered basic terminology and concepts, some mathematical foundations,  and finished up with some of the more prevalent neural net structures.  However, there is still so much more to learn about neural nets. We need  to cover <em class='bbc'>Perceptrons</em>, <em class='bbc'>Fuzzy Associative Memories</em> or <em class='bbc'>FAMs</em>, <em class='bbc'>Bidirectional Associative Memories</em> or <em class='bbc'>BAMs</em>, <em class='bbc'>Kohonen Maps</em>, <em class='bbc'>Adalines</em>, <em class='bbc'>Madalines</em>, <em class='bbc'>Backpropagation networks</em>, <em class='bbc'>Adaptive Resonance Theory networks</em>, <em class='bbc'>"Brain State in a Box",</em> and a lot more. Well that's it, my neural net wants to play N64!]]></description>
		<pubDate>Thu, 07 Oct 1999 17:24:55 +0000</pubDate>
		<guid isPermaLink="false">21be9a4bd4f81549a9d1d241981cec3c</guid>
	</item>
</channel>
</rss>
