<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule">

<channel>
	<title>Paul Kuliniewicz &#187; Wallace</title>
	<atom:link href="http://www.kuliniewicz.org/blog/archives/category/coding/wallace/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kuliniewicz.org/blog</link>
	<description>After all, it could only cost you your life, and you got that for free.</description>
	<lastBuildDate>Wed, 10 Mar 2010 03:40:24 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/us/</creativeCommons:license>		<item>
		<title>Game changer</title>
		<link>http://www.kuliniewicz.org/blog/archives/2009/09/07/game-changer/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2009/09/07/game-changer/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 03:05:12 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>
		<category><![CDATA[fceux]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[mario]]></category>
		<category><![CDATA[mega man 2]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/?p=1488</guid>
		<description><![CDATA[One of the recurring issues with Wallace, in those rare times when I&#8217;m actually working on it, is the difficulty of interfacing Wallace with the NES emulation engine.  Emulators generally aren&#8217;t written with the goal of being driven by another program; as a result my most recent effort at it involved a lot of [...]]]></description>
			<content:encoded><![CDATA[<p>One of the recurring issues with <a href="http://www.kuliniewicz.org/blog/archives/category/coding/wallace/">Wallace</a>, in those rare times when I&#8217;m actually working on it, is the difficulty of interfacing Wallace with the NES emulation engine.  Emulators generally aren&#8217;t written with the goal of being driven by another program; as a result my most recent effort at it involved a lot of ugly hacks to <a href="http://mednafen.sourceforge.net/">Mednafen</a> to make it spew some useful data to <a href="http://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29">stdout</a>, and to cleverly disguise controller inputs generated by Wallace as a movie file.</p>
<p>However, I discovered by accident while <strike>wasting time I could&#8217;ve been spending on Panflute instead of</strike> browsing the epic time sink that is <a href="http://tvtropes.org/pmwiki/pmwiki.php/">TV Tropes</a> that some modern console emulators have built-in scripting support, and in <a href="http://fceux.com/web/htdocs/">FCEUX</a>&#8217;s case, the scripting support is also part of the often-relatively-neglected Linux version.  Said scripting support offers a relatively straightforward way to write add-on code that mucks around with the game running inside the emulator, which would be orders of magnitude more elegant and maintainable than the approaches Wallace has taken up until now.</p>
<p>What do I mean by &#8220;muck around&#8221;?  Well, you could add a way to drag-and-drop enemies in <a href="http://en.wikipedia.org/wiki/Super_Mario_Bros.">Super Mario Bros.</a>:</p>
<div style="text-align: center"><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/-jbFjhBYCjg&#038;hl=en&#038;fs=1&#038;rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/-jbFjhBYCjg&#038;hl=en&#038;fs=1&#038;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div>
<p>Or give Mega Man kill-anything laser eyes (maybe he defeated <a href="http://www.youtube.com/watch?v=hKHLOo1WgDQ">Mr. Flibble</a> Man?) in <a href="http://en.wikipedia.org/wiki/Mega_Man_2">Mega Man 2</a>:</p>
<div style="text-align: center"><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/IvDXZmS2MAU&#038;hl=en&#038;fs=1&#038;rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/IvDXZmS2MAU&#038;hl=en&#038;fs=1&#038;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div>
<p>Or replace the control scheme in <a href="http://en.wikipedia.org/wiki/Super_Mario_Bros._3">Super Mario Bros. 3</a> with the one in <a href="http://en.wikipedia.org/wiki/Kirby:_Canvas_Curse">Kirby: Canvas Curse</a>, drawing platforms and obstacles on the screen using the mouse instead of having direct control over Mario:</p>
<div style="text-align: center"><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/1XNTjVScm_8&#038;hl=en&#038;fs=1&#038;rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/1XNTjVScm_8&#038;hl=en&#038;fs=1&#038;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div>
<p>Or add head-to-head network play to <a href="http://en.wikipedia.org/wiki/Tetris#Nintendo">Nintendo&#8217;s Tetris</a> game.  You know, the one that doesn&#8217;t actually <em>have</em> a multiplayer mode to begin with:</p>
<div style="text-align: center"><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/LT1eiLiMWkk&#038;hl=en&#038;fs=1&#038;rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/LT1eiLiMWkk&#038;hl=en&#038;fs=1&#038;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div>
<p>Note that all that craziness is being implemented using <a href="http://en.wikipedia.org/wiki/Lua_(programming_language)">Lua</a> scripts in the emulator, without doing any hacking of the ROMs themselves.  In FCEUX, loading a Lua script gives it control of the emulation loop and do pretty much whatever it wants, including poking around in game memory and messing with controller inputs but also doing anything else that can be done in Lua.</p>
<p>For the time being I&#8217;m not working on porting Wallace to FCEUX+Lua, but that&#8217;s mostly because I need to get <a href="https://launchpad.net/panflute">Panflute</a> in a releasable state and resurrecting Wallace right now would be too great a distraction.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2009/09/07/game-changer/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Wallace Jr. Grows On Trees</title>
		<link>http://www.kuliniewicz.org/blog/archives/2009/03/08/wallace-jr-grows-on-trees/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2009/03/08/wallace-jr-grows-on-trees/#comments</comments>
		<pubDate>Mon, 09 Mar 2009 02:12:38 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>
		<category><![CDATA[genetic programming]]></category>
		<category><![CDATA[mega man 2]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/?p=1204</guid>
		<description><![CDATA[I&#8217;ve updated Wallace Jr. to support actual genetic programming, instead of just genetic algorithms.  That is, Wallace Jr. now generates programs that try to play video games, instead of just generating predefined controller input sequences.
Naturally, the language used by Wallace Jr. for its evolved programs is extremely limited.  In fact, it&#8217;s really more [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve updated Wallace Jr. to support actual <a href="http://en.wikipedia.org/wiki/Genetic_programming">genetic programming</a>, instead of just <a href="http://en.wikipedia.org/wiki/Genetic_algorithm">genetic algorithms</a>.  That is, Wallace Jr. now generates <em>programs</em> that try to play video games, instead of just generating predefined controller input sequences.</p>
<p>Naturally, the language used by Wallace Jr. for its evolved programs is extremely limited.  In fact, it&#8217;s really more of a language for writing expressions rather than what you&#8217;d typically consider a &#8220;program&#8221;: there&#8217;s no variables or subroutines or even loops.  Here&#8217;s the entire (informal) specification of the language:</p>
<table>
<thead>
<tr>
<th>Expression</th>
<th>Definition</th>
</tr>
</thead>
<tbody>
<tr>
<td>0&#120;00, 0&#120;01, &#8230;, 0&#120;ff</td>
<td>Constants in the range 0 &#8211; 255</td>
</tr>
<tr>
<td>(+ <var>a</var> <var>b</var>)</td>
<td>Add <var>a</var> and <var>b</var>, <a href="http://en.wikipedia.org/wiki/Modular_arithmetic">modulo</a> 256</td>
</tr>
<tr>
<td>(- <var>a</var> <var>b</var>)</td>
<td>Subtract <var>b</var> from <var>a</var>, modulo 256</td>
</tr>
<tr>
<td>(* <var>a</var> <var>b</var>)</td>
<td>Multiply <var>a</var> and <var>b</var>, modulo 256</td>
</tr>
<tr>
<td>(&amp; <var>a</var> <var>b</var>)</td>
<td><a href="http://en.wikipedia.org/wiki/Bitwise_operation">Bitwise</a> AND <var>a</var> and <var>b</var></td>
</tr>
<tr>
<td>(| <var>a</var> <var>b</var>)</td>
<td>Bitwise OR <var>a</var> and <var>b</var></td>
</tr>
<tr>
<td>(^ <var>a</var> <var>b</var>)</td>
<td>Bitwise XOR <var>a</var> and <var>b</var></td>
</tr>
<tr>
<td>(ifgt <var>a</var> <var>b</var> <var>t</var> <var>f</var>)</td>
<td>If <var>a</var> &gt; <var>b</var>, return <var>t</var>; otherwise, return <var>f</var></td>
</tr>
<tr>
<td>(read <var>a</var>)</td>
<td>Return the byte at address <var>a</var> in sprite RAM</td>
</tr>
</tbody>
</table>
<p>That&#8217;s it.  By combining those operations, you can read data from sprite RAM (which among other things, will tell you where each sprite on the screen is at), do computations on them, and ultimately return a one-byte value interpreted as the next controller input.</p>
<p>Here&#8217;s an example of what a program written in this language would look like:</p>
<blockquote><p>(&amp; (+ 0&#120;1b (&amp; (&#0045; (| 0&#120;77 (^ 0&#120;60 (read 0&#120;81))) 0&#120;23) (&amp; 0&#120;10 (&amp; 0&#120;28 (read 0&#120;be))))) (^ 0&#120;56 (ifgt 0&#120;62 (read (ifgt (| (read 0&#120;a8) 0&#120;fe) 0&#120;93 0&#120;30 0&#120;34)) 0&#120;23 (ifgt (+ 0&#120;bd (read 0&#120;70)) (^ 0&#120;ef (&#0045; (read 0&#120;33) 0&#120;4d)) (+ (&amp; 0&#120;27 (&amp; 0&#120;78 (ifgt (read 0&#120;58) 0&#120;41 0&#120;76 0&#120;b6))) (^ (read 0&#120;e7) 0&#120;9c)) (+ 0&#120;b0 (read 0&#120;08))))))</p></blockquote>
<p>Strictly speaking, none of the parentheses are necessary.  Since the language uses <a href="http://en.wikipedia.org/wiki/Polish_notation">Polish notation</a> and each operation has fixed <a href="http://en.wikipedia.org/wiki/Arity">arity</a>, parsing an expression is unambiguous even without parentheses &#8212; an advantage not held by the more conventional (to the average person, anyway) use of <a href="http://en.wikipedia.org/wiki/Infix_notation">infix notation</a> for arithmetic operations.</p>
<p>In other words, the above mess means the same thing as the following mess, where parentheses have been removed to, um, change readability.  Whether readability is improved or hindered is left as an exercise for the reader.</p>
<blockquote><p>&amp; + 0&#120;1b &amp; &#0045; | 0&#120;77 ^ 0&#120;60 read 0&#120;81 0&#120;23 &amp; 0&#120;10 &amp; 0&#120;28 read 0&#120;be ^ 0&#120;56 ifgt 0&#120;62 read ifgt | read 0&#120;a8 0&#120;fe 0&#120;93 0&#120;30 0&#120;34 0&#120;23 ifgt + 0&#120;bd read 0&#120;70 ^ 0&#120;ef &#0045; read 0&#120;33 0&#120;4d + &amp; 0&#120;27 &amp; 0&#120;78 ifgt read 0&#120;58 0&#120;41 0&#120;76 0&#120;b6 ^ read 0&#120;e7 0&#120;9c + 0&#120;b0 read 0&#120;08</p></blockquote>
<p>Maybe just drawing it as an expression tree would help:</p>
<div style="text-align: center"><a href="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/03/00003intopt.png"><img src="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/03/00003intopt-300x170.png" alt="Generation 3 top performer, optimized version" title="Generation 3 top performer, optimized version" class="size-medium wp-image-1212" /><br />(click for full version)</a></div>
<p>In the tree, each term appears as a node, with the arguments to that term shown as children of the node.  Evaluation of the expression goes from the bottom up; as new subterms are evaluated, the results get passed up until you reach the root node at the top, at which time you have the value of the expression.</p>
<p>The above expression was one generated in a run of Wallace Jr. in the fourth generation using pretty much the same input <a href="http://www.kuliniewicz.org/blog/archives/2009/02/24/more-on-wallace-jr/">as last time</a>, only using trees instead of controller input sequences.  This time, the configuration looked something like this:</p>
<blockquote><p><tt>mednafen&nbsp; &nbsp; &nbsp; &nbsp; /home/paul/mednafen&#0045;eval/instdir/bin/mednafen<br />
&nbsp;<br />
buttons&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; right left up down b a<br />
rom&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; /home/paul/roms/nes/Mega Man 2 (U)&#0046;nes<br />
initial_state&nbsp;&nbsp; /home/paul/&#0046;mednafen/mcs/Mega Man 2 (U)&#0046;0527a0ee512f69e08b8db6dc97964632&#0046;nc0<br />
organism_type&nbsp;&nbsp; tree<br />
organism_size&nbsp;&nbsp; 1000<br />
organism_depth&nbsp; 7<br />
subtree_depth&nbsp;&nbsp; 4<br />
granularity&nbsp; &nbsp;&nbsp; 5<br />
population_size 500<br />
generations&nbsp; &nbsp;&nbsp; 30<br />
parallelism&nbsp; &nbsp; 2<br />
debug&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; no<br />
export_tail&nbsp; &nbsp; 1200<br />
&nbsp;<br />
metric&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; health&nbsp; &nbsp; 0&#120;06c0 1<br />
metric&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enemy&nbsp; &nbsp;&nbsp; 0&#120;06c1 1<br />
functions&nbsp; &nbsp; &nbsp;&nbsp; megaman2&#0046;py<br />
&nbsp;<br />
tournament_size&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 50<br />
homologous_crossover_rate&nbsp;&nbsp; 0<br />
arbitrary_crossover_rate&nbsp; &nbsp; 80<br />
point_mutation_rate&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 5<br />
subtree_mutation_rate&nbsp; &nbsp; &nbsp;&nbsp; 5<br />
reproduction_rate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 10<br />
&nbsp;<br />
point_mutation_probability&nbsp; 0&#0046;05<br />
crossover_leaf_probability&nbsp; 0&#0046;20</tt></p></blockquote>
<p>Here, Wallace Jr. is starting off with 500 randomly generated expression trees of maximum depth 7 &#8212; i.e., each starting tree has one root and up to seven levels below it.  Each new generation is produced through crossover (swapping one node [and its children] with a node [and its children] from another tree), point mutation (randomly changing the content of some nodes without changing its arity), subtree mutation (replacing one node and its children with a randomly generated subtree), and reproduction (copying unchanged from the previous generation).</p>
<p>The fitness graph over 30 generations looked like this:</p>
<div style="text-align: center"><img src="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/03/fitness-tree.png" alt="Fitness over 30 generations" title="Fitness over 30 generations" class="size-full wp-image-1217" /></div>
<p>It&#8217;s interesting how quickly things plateaued at a maximum fitness of 12 so quickly and never improved from there.  Something similar happened last time, but not nearly so quickly.  I&#8217;m not entirely sure why there was no improvement past a fitness of 12, but I suspect it&#8217;s because doing better than that actually requires fairly precise play.  A fitness of 12 is about what you wind up with if you consistently deal damage to Air Man but get hit by a couple tornadoes between his jumps.</p>
<p>A little manual play lends some support to this hypothesis: taking the controller myself, my own fitness ranged from 12-16 most of the time, with 20 being a personal best.  That 20 was very hard to come by, requiring some very carefully timed jumps to avoid near-unavoidable tornadoes.  In this scenario, a fitness of 12 could be the point of diminishing returns, where each incremental improvement in fitness starts being much harder to come by.</p>
<p>Actually, when I said the expression I showed earlier was one generated by Wallace Jr., I lied.  It&#8217;s actually an <em>optimized</em> version of this mess, which <em>was</em> the top performer in the fourth generation (and the first to achieve a fitness of 12):</p>
<div style="text-align: center"><a href="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/03/00003inttrue.png"><img src="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/03/00003inttrue-300x34.png" alt="Top performer of generation 3" title="Top performer of generation 3" class="size-medium wp-image-1218" /><br />(click for full version)</a></div>
<p>It&#8217;s quite a bit larger than the optimized version, since it&#8217;s doing silly things like computing (&amp; 0&#120;19 0&#120;4a) each time instead of just using a constant 0&#120;08.  That&#8217;s pretty much all the optimizer in Wallace Jr. does, mainly to make the trees it generates more readable, or at least less unreadable, by simplifying things as much as possible.</p>
<p>After the third generation, there wasn&#8217;t any improvement in peak fitness.  However, the expressions being generated tended to get bigger and bigger.  Here&#8217;s the top performer of the thirtieth generation (or really, one of the many many trees tied for top performer), optimized:</p>
<div style="text-align: center"><a href="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/03/00029intopt.png"><img src="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/03/00029intopt-300x182.png" alt="Generation 29 top performer, optimized" title="Generation 29 top performer, optimized" class="size-medium wp-image-1220" /><br />(click for full version)</a></div>
<p>And in its full, unoptimized glory:</p>
<div style="text-align: center"><a href="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/03/00029inttrue.png"><img src="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/03/00029inttrue-300x51.png" alt="Generation 29 top performer, unoptimized" title="Generation 29 top performer, unoptimized" class="size-medium wp-image-1221" /><br />(click for full version)</a></div>
<p>Interestingly, if you compare the optimized versions of the Generation 29 top performer with the Generation 3 top performer shown above, you&#8217;ll see that the top four levels of the tree are, with the exception of one node, <em>identical</em>.  This suggests the Generation 29 winner is descended from the Generation 3 winner.  It would be interesting to study the full scope of their similarities, and the similarities with the winners in the intervening generations, to what parts of the expression are so seemingly essential that they&#8217;ve been preserved from one generation to the next.</p>
<p>For the time being, doing so is also left as an exercise for the reader.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2009/03/08/wallace-jr-grows-on-trees/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>The Perils of Pipes</title>
		<link>http://www.kuliniewicz.org/blog/archives/2009/03/01/the-perils-of-pipes/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2009/03/01/the-perils-of-pipes/#comments</comments>
		<pubDate>Mon, 02 Mar 2009 02:51:20 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>
		<category><![CDATA[ipc]]></category>
		<category><![CDATA[mednafen]]></category>
		<category><![CDATA[pipe]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/?p=1177</guid>
		<description><![CDATA[In my last post, I mentioned this in regards to making Wallace Jr. and my hacked version of Mednafen:
It’s not insurmountable, but having programs talk back and forth to each other is always a bit tricky, especially to avoid deadlocks: A is waiting for B to say something, and B is waiting for A to [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.kuliniewicz.org/blog/archives/2009/02/24/more-on-wallace-jr/">In my last post</a>, I mentioned this in regards to making Wallace Jr. and my hacked version of <a href="http://mednafen.sourceforge.net/">Mednafen</a>:</p>
<blockquote><p>It’s not insurmountable, but having programs talk back and forth to each other is always a bit tricky, especially to avoid <a href="http://en.wikipedia.org/wiki/Deadlock">deadlocks</a>: A is waiting for B to say something, and B is waiting for A to say something.  Especially when B was never intended to talk to A to begin with.</p></blockquote>
<p>My prediction of running into difficulties proved to be all too accurate, even despite <em>expecting</em> problems to arise and being exceedingly careful to avoid them.  Sadly, this hardly qualifies to <a href="http://www.randi.org/site/index.php/1m-challenge.html">win the JREF prize</a>, any more than predicting that the sun will rise tomorrow would.</p>
<p>Recall what I&#8217;m trying to do here: have Wallace Jr. generate a sequence of controller inputs, have Mednafen execute them while playing a game, and have Wallace Jr. evaluate what happens in the game as a result.  This means there has to be bidirectional communication: one channel from Wallace Jr. to Mednafen, and a second from Mednafen back to Wallace Jr.</p>
<p>In the original design, the path into Mednafen was pretty simple, since the input sequence was predetermined.  Wallace Jr. generated an MCM file (a Mednafen movie file, consisting of an initial state and, well, a sequence of controller input), saved it to disk, and told Mednafen where to find it when it was launched.  Mednafen, in turn, printed out status information, which Wallace Jr. read at its leisure.</p>
<p>For those of you not familiar with programming, allow me to elaborate on that last part a bit.  Most languages provide <a href="http://en.wikipedia.org/wiki/Standard_streams">three standard input/output streams</a> to programs: one for input (<tt>stdin</tt>), one for normal output (<tt>stdout</tt>), and one for outputing error messages (<tt>stderr</tt>).  By default, when you run a program from the command line, <tt>stdin</tt> comes from the keyboard, and <tt>stdout</tt> and <tt>stderr</tt> get printed out to the terminal window.  To the program, these three streams look just like any other file; in fact, in C they&#8217;re even represented as <tt>FILE *</tt>, the same as you&#8217;d get if you called <tt>fopen</tt> to open a file.</p>
<p>Since I said <em>by default</em> the streams are connected to the keyboard and the terminal window, that obviously implies this isn&#8217;t always the case.  When you create a new process, you&#8217;re free to connect its standard streams to whatever you want.  That&#8217;s what Wallace Jr. did: when launching Mednafen, it attached its <tt>stdout</tt> stream to a pipe, so that whatever Mednafen writes to it, Wallace Jr. can read it.</p>
<p>The current version of Wallace Jr. goes one further, attaching pipes both to Mednafen&#8217;s <tt>stdout</tt> <em>and</em> <tt>stdin</tt> streams:</p>
<div class="vim"><code>child = subprocess&#0046;Popen ([self&#0046;executable_path,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;<span class="Constant">&#0045;video</span>&quot;, self&#0046;debug <span class="Statement">and</span> &quot;<span class="Constant">1</span>&quot; <span class="Statement">or</span> &quot;<span class="Constant">0</span>&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;<span class="Constant">&#0045;sound</span>&quot;, self&#0046;debug <span class="Statement">and</span> &quot;<span class="Constant">1</span>&quot; <span class="Statement">or</span> &quot;<span class="Constant">0</span>&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;<span class="Constant">&#0045;nothrottle</span>&quot;, &quot;<span class="Constant">1</span>&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;<span class="Constant">&#0045;movie</span>&quot;, &quot;<span class="Constant">/dev/stdin</span>&quot;,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;<span class="Constant">&#0045;metrics</span>&quot;, self&#0046;project_file,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self&#0046;rom_file],<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stdin=subprocess&#0046;PIPE,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stdout=subprocess&#0046;PIPE,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; close_fds=1)</code></div>
<p>But wait, you object, the arguments I&#8217;m passing to Mednafen still tell it to read its movie from a file &#8212; particularly, a file named <tt>/dev/stdin</tt>.  What gives?  <tt>/dev/stdin</tt> is just a <a href="http://en.wikipedia.org/wiki/Symbolic_link">symlink</a> to <tt>/proc/self/fd/0</tt>, which is in turn a symlink to whatever the current process&#8217;s <tt>stdin</tt> stream is.  So really, giving Medafen a file name of <tt>/dev/stdin</tt> is just telling it to read from its <tt>stdin</tt>.</p>
<p>(If that sounds like some kind of voodoo to you, keep in mind that on Unix-based systems, <em>everything</em> is a file.  Files in the conventional sense of &#8220;a bunch of bytes with a name and stored on a disk&#8221; is just one type of file &#8212; files can also be pipes or devices or almost anything else.  Everything in <tt>/proc</tt> is some type of information about the processes running on the system, exposed as a set of files.  The underlying data is stored not on disk, but in the <a href="http://en.wikipedia.org/wiki/Kernel_(computing)">kernel</a>&#8217;s internal data structures.)</p>
<p>Anyway, the ultimate goal in sending Mednafen controller inputs via a pipe instead of a file is so that, in the future, Wallace Jr. will be able to generate programs that decide the next controller input based on the current state of the game.  To do that, obviously, it needs to see the game state at time <var>t</var> before the controller input at time <var>t</var>+1 can be sent.  Writing all the controller input to a file ahead of time is right out.</p>
<p>If everything&#8217;s working, what should happen is that Wallace Jr. does a little processing, sends controller input to Mednafen, waits for Mednafen to respond with the game state, and repeats.  Meanwhile, Mednafen waits for Wallace Jr. to send it controller input, emulates the next frame of the game, sends the updated game state to Wallace Jr., and repeats.  If these ever get out of sync &#8212; namely, if both Mednafen and Wallace Jr. are waiting for the other to send something, you hit deadlock and nothing happens.</p>
<p>It&#8217;s easy to get wrong.  Here&#8217;s two examples of how things went wrong.</p>
<p>As a proof-of-concept, I initially tried having Wallace Jr. send everything at once through the pipe.  Deadlock.  However, I found that if I closed Wallace Jr.&#8217;s side of the pipe going to Mednafen, it worked!  That was weird, since I was being careful to flush the pipe after writing, to make sure the data was actually getting sent instead of sitting around in a buffer.</p>
<p>After banging my head against it for a while, I ultimately figured out that <a href="http://en.wikipedia.org/wiki/Gzip">gzip</a> was the culprit.  Normally, Mednafen movie files, which is ultimately what&#8217;s being sent to it via the pipe, are compressed with gzip, and I initially had Wallace Jr. do so as well.  Apparently, however, the code on the Mednafen side of things that handles decompression was waiting to reach the end-of-file before actually decompressing the data.  That&#8217;s why Mednafen did nothing until Wallace Jr. closed its side of the pipe, which would cause Mednafen to finally detect end-of-file.</p>
<p>Naturally, closing the pipe isn&#8217;t an option when sending controller input one frame at a time, since there&#8217;s no way to re-open a pipe once it&#8217;s closed.  Luckily, however, Mednafen is happy with getting uncompressed movie data sent to it; taking gzip out of the equation entirely fixed the problem.</p>
<p>The second deadlock I ran into took even longer to diagnose.  Here&#8217;s a simplified version of the code that triggered it.  What it&#8217;s <em>supposed</em> to do is generate the next input, send it to Mednafen&#8217;s <tt>stdin</tt>, and then read from Mednafen&#8217;s <tt>stdout</tt> until it sees a line that starts with &#8220;metrics&#8221;.  When it does, it processes it and decides whether to loop or not.  What it <em>actually</em> does is deadlock immediately when it tries to read from Mednafen.  Do you see why?</p>
<div class="vim"><code><span class="Statement">while</span> should_continue:<br />
&nbsp; &nbsp; controller_input = compute_next_input ()<br />
&nbsp;<br />
&nbsp; &nbsp; child&#0046;stdin&#0046;write (controller_input)<br />
&nbsp; &nbsp; child&#0046;stdin&#0046;flush ()<br />
&nbsp;<br />
&nbsp; &nbsp; should_continue = False<br />
&nbsp; &nbsp; <span class="Statement">for</span> line <span class="Statement">in</span> child&#0046;stdout:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">if</span> line&#0046;startswith (&quot;<span class="Constant">metrics</span>&quot;):<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; should_continue = process_metrics (line)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">break</span></code></div>
<p>Your first guess is that Mednafen isn&#8217;t actually writing any lines that start with &#8220;metrics&#8221;.  That wasn&#8217;t the problem.  Your second guess is that Mednafen isn&#8217;t flushing its output buffer, so the line isn&#8217;t getting sent through the pipe.  Wrong again.</p>
<p>Give up?  I&#8217;m not surprised &#8212; it&#8217;s <em>very</em> non-obvious.</p>
<p>The &#8220;<tt>for <var>line</var> in <var>file</var></tt>&#8221; construct in Python iterates through the contents of a file, one line at a time.  Internally, this happens by Python invoking <tt><var>file</var>.next()</tt> each time through the loop to get the next line.  Here&#8217;s what the Python manual says about <a href="http://docs.python.org/library/stdtypes.html#file.next">the <tt>next()</tt> method for file objects</a> (emphasis added):</p>
<blockquote><p>A file object is its own iterator, for example <tt>iter(f)</tt> returns <var>f</var> (unless <var>f</var> is closed). When a file is used as an iterator, typically in a <tt>for</tt> loop (for example, <tt>for line in f: print line</tt>), the <tt>next()</tt> method is called repeatedly. This method returns the next input line, or raises <tt>StopIteration</tt> when EOF is hit when the file is open for reading (behavior is undefined when the file is open for writing). In order to make a for loop the most efficient way of looping over the lines of a file (a very common operation), <strong>the <tt>next()</tt> method uses a hidden read-ahead buffer</strong>. As a consequence of using a read-ahead buffer, combining <tt>next()</tt> with other file methods (like <tt>readline()</tt>) does not work right. However, using <tt>seek()</tt> to reposition the file to an absolute position will flush the read-ahead buffer.</p></blockquote>
<p>A hidden read-ahead buffer!  <tt>next()</tt> is trying to be clever and trying to read <em>more</em> than just the next line, so it can pad out its buffer.  However, Mednafen stops and waits for more input from Wallace Jr. after outputting a line, so <tt>next()</tt> waits for input that isn&#8217;t going to come until Wallace Jr. gets back to work.  But that won&#8217;t happen until <tt>next()</tt> returns, which it won&#8217;t until it sees more input from Mednafen, even though it already has the line Wallace Jr. is asking for!  Deadlock.</p>
<p>The fix is simple enough: use <tt>readline()</tt> to get the next line of the file instead of the nice <a href="http://en.wikipedia.org/wiki/Syntactic_sugar">syntactic sugar</a> of the <tt>for</tt> loop, in order to avoid <tt>next()</tt>&#8217;s read-ahead buffer:</p>
<div class="vim"><code><span class="Statement">while</span> should_continue:<br />
&nbsp; &nbsp; controller_input = compute_next_input ()<br />
&nbsp;<br />
&nbsp; &nbsp; child&#0046;stdin&#0046;write (controller_input)<br />
&nbsp; &nbsp; child&#0046;stdin&#0046;flush ()<br />
&nbsp;<br />
&nbsp; &nbsp; should_continue = False<br />
&nbsp; &nbsp; line = child&#0046;stdout&#0046;readline ()<br />
&nbsp; &nbsp; <span class="Statement">while</span> line != &quot;&quot;:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">if</span> line&#0046;startswith (&quot;<span class="Constant">metrics</span>&quot;):<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; should_continue = process_metrics (line)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">break</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; line = child&#0046;stdout&#0046;readline ()</code></div>
<p>I would actually call <tt>next()</tt>&#8217;s behavior here a bug.  It&#8217;s perfectly reasonable for it to read past the end-of-line and buffer the excess, <em>if there&#8217;s data after the <a href="http://en.wikipedia.org/wiki/Newline">newline</a></em>.  What&#8217;s happening internally is that the data <tt>next()</tt> got from the pipe ended with a newline, and it&#8217;s going ahead and trying to read from the pipe <em>again</em> just for the sake of filling its buffer.  This actually <em>decreases</em> efficiency, since if <tt>next()</tt> isn&#8217;t going to be called again, it&#8217;s doing a read unnecessarily, at the cost of another <a href="http://en.wikipedia.org/wiki/System_call">system call</a>.  And if <tt>next()</tt> <em>is</em> going to be called again immediately, well, waiting to do the read until then doesn&#8217;t cost anything.</p>
<p>Of course, you wouldn&#8217;t notice the difference in practice, <em>unless</em> there&#8217;s no more data after the newline, but the file/pipe/whatever isn&#8217;t closed yet either.  Which is exactly what happens in Wallace Jr.&#8217;s case.</p>
<p>The moral is: even if you know how tricky bidirectional interprocess communication is, it&#8217;s still trickier than you expect.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2009/03/01/the-perils-of-pipes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>More on Wallace Jr.</title>
		<link>http://www.kuliniewicz.org/blog/archives/2009/02/24/more-on-wallace-jr/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2009/02/24/more-on-wallace-jr/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 03:56:18 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>
		<category><![CDATA[genetic algorithm]]></category>
		<category><![CDATA[mega man 2]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/?p=1167</guid>
		<description><![CDATA[To elaborate somewhat on my previous post, this is the input file I gave to Wallace Jr. in the run used to ultimately generate that video:
mednafen&#160; &#160; &#160; &#160; /home/paul/mednafen&#0045;eval/instdir/bin/mednafen
&#160;
buttons&#160; &#160; &#160; &#160;&#160; right left up down b a
rom&#160; &#160; &#160; &#160; &#160; &#160;&#160; /home/paul/roms/nes/Mega Man 2 (U)&#0046;nes
initial_state&#160;&#160; /home/paul/&#0046;mednafen/mcs/Mega Man 2 (U)&#0046;0527a0ee512f69e08b8db6dc97964632&#0046;nc0
organism_size&#160;&#160; 1000
granularity&#160; &#160;&#160; 5
population_size [...]]]></description>
			<content:encoded><![CDATA[<p>To elaborate somewhat on <a href="http://www.kuliniewicz.org/blog/archives/2009/02/22/the-return-of-wallace/">my previous post</a>, this is the input file I gave to Wallace Jr. in the run used to ultimately generate that video:</p>
<blockquote><p><tt>mednafen&nbsp; &nbsp; &nbsp; &nbsp; /home/paul/mednafen&#0045;eval/instdir/bin/mednafen<br />
&nbsp;<br />
buttons&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; right left up down b a<br />
rom&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; /home/paul/roms/nes/Mega Man 2 (U)&#0046;nes<br />
initial_state&nbsp;&nbsp; /home/paul/&#0046;mednafen/mcs/Mega Man 2 (U)&#0046;0527a0ee512f69e08b8db6dc97964632&#0046;nc0<br />
organism_size&nbsp;&nbsp; 1000<br />
granularity&nbsp; &nbsp;&nbsp; 5<br />
population_size 200<br />
generations&nbsp; &nbsp;&nbsp; 50<br />
parallelism&nbsp; &nbsp; 2<br />
&nbsp;<br />
metric&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; health&nbsp; &nbsp; 0x06c0 1<br />
metric&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enemy&nbsp; &nbsp;&nbsp; 0x06c1 1<br />
functions&nbsp; &nbsp; &nbsp;&nbsp; megaman2&#0046;py<br />
&nbsp;<br />
tournament_size&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 50<br />
homologous_crossover_rate&nbsp;&nbsp; 40<br />
arbitrary_crossover_rate&nbsp; &nbsp; 40<br />
point_mutation_rate&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 10<br />
reproduction_rate&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 10<br />
&nbsp;<br />
point_mutation_probability&nbsp; 0&#0046;01</tt></p></blockquote>
<p>Note that the run used populations of 200 candidate solutions per generation.  Each initial solution was 1,000 inputs long, with input granularity set to 5 frames &#8212; i.e., the same button input would be used for 5 consecutive frames (about 1/12 of a second) before advancing to the next.  This was used to prevent solutions from being to spastic.</p>
<p>The various <tt>_rate</tt> settings specify how to generate new solutions from existing ones:</p>
<ul>
<li><strong>Homologous crossover</strong> takes one solution, deletes a randomly selected range within it, and replaces it with the corresponding range from another solution.</li>
<li><strong>Arbitrary crossover</strong> is similar, but doesn&#8217;t require the two ranges to correspond to one another.</li>
<li><strong>Point mutation</strong> randomly mutates each input with some small probability (here, 1%).</li>
<li><strong>Reproduction</strong> just copies a solution unchanged from the previous generation.</li>
</ul>
<p>When picking solutions for any of these techniques, Wallace Jr. uses a basic form of <a href="http://en.wikipedia.org/wiki/Tournament_selection">tournament selection</a>.  In tournament selection, you take a random subset of the population and pick the element with the highest fitness.  This way, fitter solutions will get selected more frequently than less fit ones, but there&#8217;s still some randomness in the process.  After all, if you always picked the fittest organism, you&#8217;d eliminate all the diversity in the population.</p>
<p>The <tt>metric</tt> lines specify addresses in game memory that store interesting values.  Here, it&#8217;s the health of Mega Man and of the boss of the stage.  Each is just one byte, which makes things easy.  These values are actually ignored by Wallace Jr. itself; instead, my hacked copy of Mednafen uses these to decide what values to output after each frame.</p>
<p>For the actual fitness function, I decided to just specify those in Python instead of coming up with some way to express it in the configuration file.  Here&#8217;s what <tt>megaman2.py</tt> has in it:</p>
<div class="vim"><code><span class="Comment">#! /usr/bin/env python</span><br />
&nbsp;<br />
<span class="Statement">def</span> <span class="Identifier">compute_fitness</span> (current_metrics, old_metrics, context):<br />
&nbsp; &nbsp; &quot;&quot;&quot;<br />
<span class="Constant">&nbsp; &nbsp; Reward damage done to the enemy and health preserved&#0046;&nbsp; Penalize runs that</span><br />
<span class="Constant">&nbsp; &nbsp; end before someone dies via a penalty for frames where both are still</span><br />
<span class="Constant">&nbsp; &nbsp; alive&#0046;&nbsp; Also try to penalize activation of the door glitch by watching</span><br />
<span class="Constant">&nbsp; &nbsp; for increases in health, which indicate death&#0045;by&#0045;spikes&#0046;</span><br />
<span class="Constant">&nbsp; &nbsp; </span>&quot;&quot;&quot;<br />
&nbsp;<br />
&nbsp; &nbsp; <span class="Statement">def</span> <span class="Identifier">increased</span> (key):<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">return</span> key <span class="Statement">in</span> old_metrics <span class="Statement">and</span> current_metrics[key] &gt; old_metrics[key]<br />
&nbsp;<br />
&nbsp; &nbsp; fitness = current_metrics[&quot;<span class="Constant">health</span>&quot;] &#0045; current_metrics[&quot;<span class="Constant">enemy</span>&quot;]<br />
&nbsp; &nbsp; <span class="Statement">if</span> &quot;<span class="Constant">battle_started</span>&quot; <span class="Statement">not</span> <span class="Statement">in</span> context:<br />
&nbsp; &nbsp; &nbsp; &nbsp; fitness &#0045;= 500<br />
&nbsp; &nbsp; <span class="Statement">if</span> current_metrics[&quot;<span class="Constant">health</span>&quot;] &gt; 0 <span class="Statement">and</span> current_metrics[&quot;<span class="Constant">enemy</span>&quot;] &gt; 0:<br />
&nbsp; &nbsp; &nbsp; &nbsp; fitness &#0045;= 100<br />
&nbsp; &nbsp; <span class="Statement">if</span> increased (&quot;<span class="Constant">health</span>&quot;):<br />
&nbsp; &nbsp; &nbsp; &nbsp; fitness &#0045;= 500<br />
&nbsp; &nbsp; <span class="Statement">return</span> fitness<br />
&nbsp;<br />
<span class="Statement">def</span> <span class="Identifier">should_terminate</span> (current_metrics, old_metrics, context):<br />
&nbsp; &nbsp; &quot;&quot;&quot;<br />
<span class="Constant">&nbsp; &nbsp; Terminate once someone dies or the aforementioned sign of the door</span><br />
<span class="Constant">&nbsp; &nbsp; glitch is observed&#0046;</span><br />
<span class="Constant">&nbsp; &nbsp; </span>&quot;&quot;&quot;<br />
&nbsp;<br />
&nbsp; &nbsp; <span class="Statement">def</span> <span class="Identifier">dropped_to_zero</span> (key):<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">return</span> current_metrics[key] == 0 <span class="Statement">and</span> key <span class="Statement">in</span> old_metrics <span class="Statement">and</span> old_metrics[key] &gt; 0<br />
&nbsp; &nbsp; <span class="Statement">def</span> <span class="Identifier">increased</span> (key):<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="Statement">return</span> key <span class="Statement">in</span> old_metrics <span class="Statement">and</span> current_metrics[key] &gt; old_metrics[key]<br />
&nbsp;<br />
&nbsp; &nbsp; <span class="Statement">if</span> &quot;<span class="Constant">battle_started</span>&quot; <span class="Statement">not</span> <span class="Statement">in</span> context <span class="Statement">and</span> increased (&quot;<span class="Constant">enemy</span>&quot;) <span class="Statement">and</span> current_metrics [&quot;<span class="Constant">enemy</span>&quot;] == 28:<br />
&nbsp; &nbsp; &nbsp; &nbsp; context[&quot;<span class="Constant">battle_started</span>&quot;] = True<br />
&nbsp;<br />
&nbsp; &nbsp; <span class="Statement">return</span> dropped_to_zero (&quot;<span class="Constant">health</span>&quot;) <span class="Statement">or</span> dropped_to_zero (&quot;<span class="Constant">enemy</span>&quot;) <span class="Statement">or</span> increased (&quot;<span class="Constant">health</span>&quot;)</code></div>
<p>The interface between Wallace Jr. and the fitness code can definitely stand to be improved.  The functions are passed the current values of the metrics, the previous values of the metrics, and a context value it&#8217;s free to manipulate as it chooses to save information between calls.  Most of the complexity is to handle the cases I mentioned in the previous post about avoiding undesirable outcomes like running out of input or activating the door glitch.</p>
<p>The astute reader will notice that I ran things out to 50 generations, but the video only shows examples up through Generation 13.  Why?  This:</p>
<div style="text-align: center"><img src="http://www.kuliniewicz.org/blog/wp-content/uploads/2009/02/fitness.png" alt="Fitness of Wallace Jr. run" title="Fitness of Wallace Jr. run" class="size-full wp-image-1172" /></div>
<p>Things kind of hit a wall after Generation 13, with no real improvement any way you look at things.  I suspect this was due to a combination of a fairly small generation size (200) and having 80% of each generation produced by crossover of existing solutions, with only 10% undergoing a handful of point mutations.  Presumably, around the time Generation 13 was reached, the population had become a sort of inbred monoculture with little diversity between organisms, meaning it would take a long time for beneficial mutations to arise.</p>
<p>Sadly, I don&#8217;t have any way to go back and test this hypothesis, since the only organisms I saved were the peak performers of each generation.  It may be worthwhile for later versions to compute <a href="http://en.wikipedia.org/wiki/Hamming_distance">Hamming distances</a> or something like that to get a measure of how much diversity is in the population, and see how that changes over time.</p>
<p>One big limitation to Wallace Jr. currently is that it evolves input sequences, which are inherently going to be very specific to the initial state of the game when the solution starts playing it.  In other words, if I played up to Air Man in a different playthrough and handed control off to the peak performer, it wouldn&#8217;t do nearly as well, since the state of the game wouldn&#8217;t match up with what it &#8220;expects&#8221;.</p>
<p>It&#8217;s like if you memorized the directions for getting to the store as a series of turns to make at each intersection &#8212; right, left, straight, right, right, etc.  You&#8217;d do fine, unless I had you start a block or two over from your expected starting point.  Suddenly, the directions are no longer correct.</p>
<p>What would be more interesting is to evolve <em>programs</em> to play the game, rather than mere input sequences.  Of course, this would be a fair bit more difficult to implement, since now the solutions will need a way to observe the state of the game as part of their computation of what button input to produce.  One way to do this would be to let it inspect the part of PPU memory where sprite information is stored, sort of letting it &#8220;read&#8221; what sprites are on the screen and where they&#8217;re at.  The tricky part is getting Wallace Jr. and Mednafen to talk to each other like that while the emulation is going on &#8212; right now Wallace Jr. generates a Mednafen movie file and hands it off to Mednafen to play.</p>
<p>It&#8217;s not insurmountable, but having programs talk back and forth to each other is always a bit tricky, especially to avoid <a href="http://en.wikipedia.org/wiki/Deadlock">deadlocks</a>: A is waiting for B to say something, and B is waiting for A to say something.  Especially when B was never intended to talk to A to begin with.</p>
<p>If you&#8217;re interested in learning more about the theory behind genetic algorithms and genetic programming, you may want to take a look at <a href="http://www.lulu.com/content/2167025">A Field Guide to Genetic Programming</a>, which is a freely downloadable book.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2009/02/24/more-on-wallace-jr/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The return of Wallace!</title>
		<link>http://www.kuliniewicz.org/blog/archives/2009/02/22/the-return-of-wallace/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2009/02/22/the-return-of-wallace/#comments</comments>
		<pubDate>Mon, 23 Feb 2009 03:49:18 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>
		<category><![CDATA[air man]]></category>
		<category><![CDATA[genetic algorithm]]></category>
		<category><![CDATA[mega man 2]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/?p=1159</guid>
		<description><![CDATA[For whatever reason, I recently got it in my head to take another stab at my long-since-abandoned effort to apply genetic algorithms to the utterly pointless task of playing old video games.  Here&#8217;s the result:

The gruntwork seen above was done using Wallace Jr., which as its name suggests, is a significantly stripped-down version of [...]]]></description>
			<content:encoded><![CDATA[<p>For whatever reason, I recently got it in my head to take another stab at my long-since-abandoned effort to apply <a href="http://en.wikipedia.org/wiki/Genetic_algorithm">genetic algorithms</a> to the utterly pointless task of playing old video games.  Here&#8217;s the result:</p>
<div style="text-align: center"><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/c7xJNAJys2s&#038;hl=en&#038;fs=1&#038;rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/c7xJNAJys2s&#038;hl=en&#038;fs=1&#038;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div>
<p>The gruntwork seen above was done using <a href="http://code.kuliniewicz.org/wallace_jr/main/changes">Wallace Jr.</a>, which as its name suggests, is a significantly stripped-down version of Wallace, my original attempt from a couple years back.  Wallace&#8217;s ultimate failing was trying to do a little bit of everything: being a graphical emulator front-end, reverse engineering memory locations, doing the genetic algorithm itself, video encoding, etc.  As a result, it did none particularly well, and continuing problems trying to shoehorn <a href="http://gstreamer.freedesktop.org/">GStreamer</a> into the processing pipeline ultimately led to its abandonment.</p>
<p>Instead, Wallace Jr. just does the genetic algorithm stuff: generating organisms, evaluating them, and spawning new generations.  That&#8217;s it.  The emulation itself is passed off to a modified version of <a href="http://mednafen.sourceforge.net/">Mednafen</a> &#8212; specifically, a version hacked to enable noninteractive use and to dump interesting memory values while executing.  The actual reverse engineering bit is left to something else; it accepts a list of memory locations to use as metrics when evaluating fitness, but leaves it up to you to find a way to figure them out.</p>
<p>As a result, Wallace Jr. accomplishes its core mission without getting bogged down in other things.  Also, by offloading emulation into a separate process, it has the nice side benefit of enabling parallelism, since for whatever reason emulator authors seem to love <a href="http://en.wikipedia.org/wiki/Global_variable">global variables</a> for all important state, which pretty much eliminates any hope of emulating more than one thing at a time in the same memory space.</p>
<p>Wallace Jr. is still pretty basic, but it&#8217;s still complete enough to generate the results in the video, wherein a set of controller inputs capable of defeating Air Man in <a href="http://en.wikipedia.org/wiki/Mega_Man_2">Mega Man 2</a> in just 11 generations.  In that demonstration, fitness is basically defined as Mega Man&#8217;s health minus Air Man&#8217;s health, with the goal of maximizing the fitness measure.</p>
<p>I say &#8220;basically&#8221; because genetic algorithms, much like biological evolution, is prone to finding clever ways to solve problems, and the naive fitness measure I just described lets some of these slip through.  In particular, if input ends before either Air Man or Mega Man dies, the fitness will still be the difference between their health meters.  If input ends <em>really</em> early, like, say, before the battle starts when Air Man has nominally zero health, the outcome is the optimal fitness measure of 28, even though that solution really isn&#8217;t what we want.  The real fitness measure I used checks for that, and throws in a -100 penalty if input ends before a death, and a -500 penalty on top of that if the battle hasn&#8217;t even begun yet.</p>
<p>More amusingly, seen in the &#8220;outtake&#8221; at the end of the video, in one of the runs I attempted while developing Wallace Jr., it managed to randomly hit upon controller input that activated the <a href="http://www.flyingomelette.com/oddities/mm2glitch.html">Air Man door glitch</a>.  I didn&#8217;t even know that was <em>possible</em> without using Item 1, but apparently it is.  I had to adjust the fitness function to penalize that as well.</p>
<p>I hope you appreciate that video, since it took a ridiculous amount of effort to make.  For starters, Mednafen doesn&#8217;t have a way to output a normal video file &#8212; the movies it makes are just recordings of controller input.  Hacking in a way to dump the raw audio samples to a file was simple enough, but video proved to be more problematic; raw video data is too large to write to a file without making the emulator horrifically I/O-bound, disrupting emulation as it tries to frame-skip to recover.  Integrating a true video encoder into Mednafen was more work than I wanted to do, so I took the extraordinarily hackish solution of adding a way to dump <a href="http://en.wikipedia.org/wiki/Portable_Network_Graphics">PNG</a> screenshots every couple frames (since doing it every frame ran into the same I/O issues).</p>
<p>Luckily, <a href="http://en.wikipedia.org/wiki/MEncoder">MEncoder</a> has a way to convert a series of PNGs into a more conventional video file, but that still left the issue of stitching them all together into a single movie.  I managed to use <a href="http://en.wikipedia.org/wiki/PiTiVi">PiTiVi</a> for that, despite its best efforts to be a bug-ridden half-working pile of something you&#8217;d <a href="http://en.wikipedia.org/wiki/Dirty_Jobs">expect to find Mike Rowe knee-deep in</a>.  Sadly, the alternatives for non-linear video editing on Linux are even worse.</p>
<p>The interstitials were a pain to make, since PiTiVi doesn&#8217;t provide a way to add captions to video clips.  For that, I wound up manually putting together a GStreamer stream via <tt>gst-launch-0.10</tt> and the <tt>textoverlay</tt> element.  The trick there was making sure to encode the resulting video stream in a format that GStreamer could then read back when used by PiTiVi.  For some reason, GStreamer will happily encode to lossless <a href="http://en.wikipedia.org/wiki/Motion_JPEG">MJPEG</a> but has no idea how to decode it!</p>
<p>Once that was finally done, I switched back to MEncoder to add the background music.  Yes, I know the last note gets cut off at the end, but I wasn&#8217;t about to wrestle with PiTiVi again to lengthen the video by a couple seconds, especially given that PiTiVi <em>doesn&#8217;t let you save your project</em>!  The mind boggles.</p>
<p>Splicing in a separate audio track also nicely hides how my hack of dumping screenshots rapid-fire instead of making a proper video causes synchronization problems when trying to combine it back with the dumped audio.  I could never get the framerate quite right, but without the original audio, it&#8217;s more difficult to notice in the video.</p>
<p>Plus, it&#8217;s an appropriate song, even if its central premise gets refuted by Generation 10.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2009/02/22/the-return-of-wallace/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Wallace: Behind the Scenes</title>
		<link>http://www.kuliniewicz.org/blog/archives/2007/11/20/wallace-behind-the-scenes/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2007/11/20/wallace-behind-the-scenes/#comments</comments>
		<pubDate>Wed, 21 Nov 2007 04:35:25 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Meta]]></category>
		<category><![CDATA[Wallace]]></category>
		<category><![CDATA[feedback]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/archives/2007/11/20/wallace-behind-the-scenes/</guid>
		<description><![CDATA[Out of curiousity, how interested are people in reading about the technical details behind the Wallace rewrite?  I could write up a couple posts about some of the technical challenges encountered and/or achievements made since the last update, but there&#8217;s not all that much in the way of stuff that can be shown off.
For [...]]]></description>
			<content:encoded><![CDATA[<p>Out of curiousity, how interested are people in reading about the technical details behind the Wallace rewrite?  I could write up a couple posts about some of the technical challenges encountered and/or achievements made since the last update, but there&#8217;s not all that much in the way of stuff that can be shown off.</p>
<p>For example, does anyone want to hear about how user input is collected?  Or maintaining audio/video synchronization and minimizing audio lag?  Or performing caps negotiation with downstream elements in the processing pipeline?  (I&#8217;ve certainly learned quite a bit on that last one over the past couple days.)  There&#8217;s interesting stuff there for anyone who wants to know more about writing GStreamer elements or who is just curious about what kind of processing is needed to make Wallace work.</p>
<p>I&#8217;ll probably write about <em>some</em> of this stuff anyway, if only to have it out there and Googleable for anyone that&#8217;s interested.  But if there&#8217;s not a whole lot of interest in that sort of thing, that&#8217;ll set the bar higher for deciding what&#8217;s blogworthy about Wallace development, especially given that there&#8217;s a non-trivial investment in time preparing a post about something like that.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2007/11/20/wallace-behind-the-scenes/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>GStreamer audio sinks are picky</title>
		<link>http://www.kuliniewicz.org/blog/archives/2007/11/13/gstreamer-audio-sinks-are-picky/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2007/11/13/gstreamer-audio-sinks-are-picky/#comments</comments>
		<pubDate>Wed, 14 Nov 2007 03:54:14 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>
		<category><![CDATA[audio sink]]></category>
		<category><![CDATA[crash]]></category>
		<category><![CDATA[gstreamer]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/archives/2007/11/13/gstreamer-audio-sinks-are-picky/</guid>
		<description><![CDATA[If you ever get the urge to write your own GStreamer element, and one of the things your element will output is an audio stream, I have a word of advice that might save you a fair amount of frustration.
All of the typical sink elements that output an audio stream to a sound card (such [...]]]></description>
			<content:encoded><![CDATA[<p>If you ever get the urge to <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/index.html">write your own</a> <a href="http://gstreamer.freedesktop.org/">GStreamer</a> element, and one of the things your element will output is an audio stream, I have a word of advice that might save you a fair amount of frustration.</p>
<p>All of the typical sink elements that output an audio stream to a sound card (such as alsasink, esdsink, osssink, or even gconfaudiosink, which after all is probably just going to wrap one of the first three) require that your buffer offsets be measured according to the stream time (<code>GST_FORMAT_TIME</code>), and not any other way.  It doesn&#8217;t matter if the caps you negotiated for your source pad clearly specified the sample size and rate, or even that you&#8217;re setting the timestamp for each of your buffers.  If your offsets don&#8217;t use <code>GST_FORMAT_TIME</code>, it won&#8217;t work.</p>
<p>Specifically, you&#8217;ll wind up with this critical error message spit out by one of the base classes most of the audio sinks shipped with GStreamer inherit from:</p>
<blockquote><p><code>GStreamer&#0045;CRITICAL **: gst_segment_clip: assertion `segment&#0045;>format == format' failed</code></p></blockquote>
<p>And that&#8217;s because that base class hard-codes <code>GST_FORMAT_TIME</code> as the segment format in its call to <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstSegment.html#gst-segment-clip"><code>gst_segment_clip</code></a>.</p>
<p>Note that the error message you get doesn&#8217;t clearly say that <em>this</em> is the reason it fails, unless you happen to install the debugging symbols for all the GStreamer libraries and plugins, and then go into a debugger to see what&#8217;s calling that function (after remembering to set the <code>G_DEBUG</code> environment variable to <code>fatal_criticals</code> so you get a core dump at the site of the problem), and <em>then</em> look up that part of the GStreamer source code to find out about the hard-coded use of <code>GST_FORMAT_TIME</code>.</p>
<p>Now, for those of you who notice what category this was posted under, yes, this means I&#8217;ve been tinkering with Wallace again.  In particular, I&#8217;m completely rewriting how it uses GStreamer to output audio and video streams from the emulator into something useful (i.e., either playing the streams or encoding them to a video file).  I&#8217;ve come to the conclusion that my old methodology was fundamentally completely wrong, and it&#8217;s a wonder I was able to make it work at all, kind of sort of.</p>
<p>This time, I&#8217;m having GStreamer drive execution of the emulator itself, instead of handling that on my own and trying to shovel its output into the pipeline, which makes scheduling and timing really really brittle.  Now, each time GStreamer thinks the emulator should produce some more output, it will call (through the nesemulator element I&#8217;m writing) the emulator more or less directly.  This ends up simplifying a good chunk of code, since GStreamer is (naturally) pretty good at figuring out when it needs more output data.  At least, GStreamer is going to do a much better job than my abusing <a href="http://library.gnome.org/devel/glib/stable/glib-The-Main-Event-Loop.html#g-idle-add"><code>g_idle_add</code></a> and <a href="http://opengroup.org/onlinepubs/007908799/xsh/nanosleep.html"><code>nanosleep</code></a>.</p>
<p>Also, instead of treating nesemulator as a source element, it will act as a decoder element.  So what input stream does it take?  Why, a sequence of button inputs, of course!  GStreamer&#8217;s fakesrc can be coaxed into providing a null input for testing nesemulator quite nicely.  Of course, I&#8217;ll need to write a new element to poll user input and convert that into the right button presses, but I was going to have to do that in one way or another anyway.  Even better, this approach provides a cleaner way to implement playback of <a href="http://en.wikipedia.org/wiki/FCE_Ultra">FCEU</a> movie files: write another element that decodes a .fcm file into the corresponding input sequence, and stream that into the nesemulator element.</p>
<p>In fact, this approach can also be used to write an <a href="http://en.wikipedia.org/wiki/NES_Sound_Format">NSF</a> decoder element, by wrapping the nesemulator element, discarding its video output, and controlling selection of which song to play.  If you were ever longing to listen to 8-bit music in <a href="http://www.gnome.org/projects/rhythmbox/">Rhythmbox</a>, that&#8217;d let you do it.</p>
<p>For the moment, though, I just have a rough but functional implementation of nesemulator, which lets you do simple stuff like this:</p>
<blockquote><p><code>gst&#0045;launch&#0045;0&#0046;10 fakesrc sizetype=2 sizemin=4 sizemax=4 filltype=2 ! nesemulator name=emu location=Mega&#0092; Man&#0092; 2&#0092; &#0092;(U&#0092;)&#0046;nes emu&#0046;video_src ! queue ! ffmpegcolorspace ! xvimagesink emu&#0046;audio_src ! queue ! audioconvert ! alsasink</code></p></blockquote>
<p>You know, in case you get the urge to <a href="http://www.youtube.com/watch?v=N8Ao63nmzuE">watch the intro to one of the greatest video games of all time</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2007/11/13/gstreamer-audio-sinks-are-picky/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>What happened to Wallace anyway?</title>
		<link>http://www.kuliniewicz.org/blog/archives/2007/08/21/what-happened-to-wallace-anyway/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2007/08/21/what-happened-to-wallace-anyway/#comments</comments>
		<pubDate>Wed, 22 Aug 2007 02:39:24 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/archives/2007/08/21/what-happened-to-wallace-anyway/</guid>
		<description><![CDATA[So it&#8217;s been several months since the last Wallace update.  What&#8217;s been going on since then.  Well, not much.
It may surprise you, but the main reason I sort of wandered away from it has been frustration with getting GStreamer to do what I wanted it to.  I wanted to use GStreamer for [...]]]></description>
			<content:encoded><![CDATA[<p>So it&#8217;s been several months since <a href="http://www.kuliniewicz.org/blog/archives/2007/02/26/wallace-0991-released/">the last Wallace update</a>.  What&#8217;s been going on since then.  Well, not much.</p>
<p>It may surprise you, but the main reason I sort of wandered away from it has been frustration with getting <a href="http://gstreamer.freedesktop.org/">GStreamer</a> to do what I wanted it to.  I wanted to use GStreamer for the audio/video output since then I effectively get video encoding for free: it&#8217;s just a matter of building a pipeline that sends the output to a video file instead of the screen and speakers.</p>
<p>However, my skills at writing GStreamer elements are wanting at best, and the fact that the design I was going for &#8212; a real-time source that has separate audio and video sources &#8212; was a bit more advanced than what&#8217;s covered in the beginners&#8217; documentation.  Everything suddenly got to a point where sending the A/V to the speakers and screen would either hang the program or cause a very noticable amount of desync.  I think I also managed to track part of it to a bug in GStreamer at the time, which presumably has since been fixed, but I never really went back to the code after throwing my hands up.</p>
<p>On the actual what-the-program-is-supposed-to-be-doing front, I&#8217;ve come to the conclusion that to do things &#8220;right&#8221; would require having some degree of debugging/disassembly features in Wallace, to allow you to pick apart the game and figure out what&#8217;s going on inside it.  There&#8217;s some things &#8212; in particular, determining the player&#8217;s position within a level &#8212; that just can&#8217;t be done without getting at whatever internal state the game uses to keep track of it.</p>
<p>Of course, doing that would entail treating the emulator code (which I took from <a href="http://en.wikipedia.org/wiki/FCE_Ultra">FCE Ultra</a>) less like a black box.  While the emulation itself is pretty solid, the source code to it, while not quite being <a href="http://worsethanfailure.com/">WTF-worthy</a>, is hardly the easiest thing to understand, especially if you aren&#8217;t intimitely familiar with the NES&#8217;s internals.</p>
<p>Reverse engineering a game is certainly possible.  After all, ROM hacks aren&#8217;t hard to find &#8212; for example, look <a href="http://www.kuliniewicz.org/blog/archives/2007/08/20/thank-goodness-i-have-w-blue-sky-lives/">one post down</a> &#8212; and can certainly require a good understanding of the game&#8217;s code and data to pull off.  It&#8217;s just that that&#8217;s more effort that would be required to have some degree of reverse engineering support in Wallace.</p>
<p>And looking farther out, assuming everything else gets worked out, it all comes down to how much processing power you can throw at &#8220;growing&#8221; your &#8220;solution&#8221;.  And unless someone suddenly donates me a 500 <a href="http://en.wikipedia.org/wiki/Yotta-">Y</a>Hz processor, that&#8217;ll involve distributed computing, which to implement well would require (among other things) splitting the emulator core and the genetic algorithm into separate libraries, to minimize the dependencies on the distributed client code.  Which wouldn&#8217;t be all <em>that</em> difficult in principle, as FCE Ultra already had a quasi-library-like interface, but it was geared towards code that got directly linked in, and the function calls went both ways.  So, it&#8217;s just one more thing to clean up.</p>
<p>Plus, having gotten distracted by a <a href="http://www.kuliniewicz.org/blog/archives/2007/08/16/only-old-ladies-play-bridge/">shiny new thing to work on</a> is only going to delay things further.  I&#8217;d at least like to get its AI to the point where it can&#8217;t be beaten by whatever&#8217;s been growing in my old college dorm refridgerator for the past five years or so before running off to something else.</p>
<p>So, to answer <a href="http://www.kuliniewicz.org/blog/archives/2007/08/20/thank-goodness-i-have-w-blue-sky-lives/#comment-1540">your question</a> <a href="http://www.auriga.blogspot.com/">Ryan</a>, in theory, yes, Wallace could play it.  In theory.  In theory, communism works.  In theory.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2007/08/21/what-happened-to-wallace-anyway/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wallace 0.99.1 Released</title>
		<link>http://www.kuliniewicz.org/blog/archives/2007/02/26/wallace-0991-released/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2007/02/26/wallace-0991-released/#comments</comments>
		<pubDate>Tue, 27 Feb 2007 03:02:02 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/archives/2007/02/26/wallace-0991-released/</guid>
		<description><![CDATA[I finally got around to tinkering with Wallace, the tool for using genetic algorithms to play Nintendo games, again.  The latest version of the software has several new features, a couple of which I&#8217;ll mention here.
The biggest is that your solutions can now take the form of a button input sequence, instead of being [...]]]></description>
			<content:encoded><![CDATA[<p>I finally got around to tinkering with Wallace, the tool for using genetic algorithms to play Nintendo games, again.  The latest version of the software has several new features, a couple of which I&#8217;ll mention here.</p>
<p>The biggest is that your solutions can now take the form of a button input sequence, instead of being a program that runs in a VM and generates button input.  This has the advantage of producing interesting results a lot faster, at the cost of your solutions being tied to your initial conditions.  So, while you might be able to generate something that plays a particular Dr. Mario screen very well, it will crash and burn on any different starting condition &#8212; it&#8217;s just a dumb sequence of moves, after all.</p>
<p>There are many other, more subtle, improvements to the evolver as well.  The selection phase now uses <a href="http://en.wikipedia.org/wiki/Tournament_selection">tournament selection</a> to choose who lives on to the next generation, instead of just taking the top <var>n</var> solutions so far.  This lets you vary selection pressure from brutal (top <var>n</var>) to nonexistent (creationists&#8217; &#8220;evolution is entirely random&#8221; <a href="http://en.wikipedia.org/wiki/Straw_man">strawman</a>) and anywhere in between.  You can also now set the rate of mutation to a much wider range, in particular setting it to rates far lower than the (ridiculously high) minimum available in the <a href="http://www.kuliniewicz.org/blog/archives/2006/11/19/about-smegging-time-or-wallace-0990-is-out/">previous version</a>.</p>
<p>Also, the evolver prompts you to save your progress before it closes.  I can&#8217;t tell you how many times the lack of that feature has caused me to lose a lot of data.</p>
<p>So, how do things shape up now?  Here&#8217;s the statistics from a relatively quick sample run, on the same Dr. Mario screen as last time.  Now, however, I&#8217;m using button input sequences with Select and Start filtered out (you can do that now too), with a population ranging from 200 to 2000 solutions, with fairly mild selection pressure (15%ish?), with a maximum mutation rate of 20 mutations per organism.  The fitness function now measures final score, with penalties for the time intervals between each time you earn points.  So, if you score 300 points at time 5 and 900 points at time 15, your fitness is 300 &#8211; 5 + 900 &#8211; (15 &#8211; 5) = 1185.  (The ability to express that kind of fitness function is another new feature.)</p>
<p>So, here&#8217;s the stats (did I mention collecting these statistics is another new feature?):</p>
<table style="text-align: right">
<thead>
<tr>
<th>Generation</th>
<th>Maximum</th>
<th>Minimum</th>
<th><a href="http://en.wikipedia.org/wiki/Arithmetic_mean">Mean</a></th>
<th><a href="http://en.wikipedia.org/wiki/Median">Median</a></th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2369</td>
<td>-1</td>
<td>39</td>
<td>0</td>
</tr>
<tr>
<td>2</td>
<td>2369</td>
<td>-1</td>
<td>348</td>
<td>287</td>
</tr>
<tr>
<td>3</td>
<td>2969</td>
<td>-1</td>
<td>985</td>
<td>893</td>
</tr>
<tr>
<td>4</td>
<td>3272</td>
<td>-1</td>
<td>1405</td>
<td>1781</td>
</tr>
<tr>
<td>5</td>
<td>4170</td>
<td>-1</td>
<td>1518</td>
<td>2369</td>
</tr>
<tr>
<td>6</td>
<td>4181</td>
<td>-1</td>
<td>1947</td>
<td>2370</td>
</tr>
</tbody>
</table>
<p>A few observations</p>
<ul>
<li>A 100% randomly generated solution <em>still</em> managed to score 2400 points in the first generation.</li>
<li>By the sixth generation, at least half the solutions are better than the best solution in the first generation.</li>
<li>Each generation, the mean and median fitness increases.</li>
<li>It should be impossible for the fitness to be -1 with the fitness function I defined.  There&#8217;s a bug somewhere.</li>
<li>Even so, the minimum shows no improvement from generation to generation; mutations can still render a good solution bad.</li>
</ul>
<p>Of course, you want to see that top solution in the sixth generation, don&#8217;t you?  Well, unlike the VM-based ones from last time, which ended up doing the same thing over and over, these solutions look like they&#8217;re being played by a monkey on crack who occasionally makes a really good move.  Of course, since my lease doesn&#8217;t cover monkeys and <a href="http://en.wikipedia.org/wiki/Vacuous_truth">none of my crack dealers are returning my calls</a>, the monkey-on-crack theory is only a hypothesis.</p>
<p>Anyway, here&#8217;s the video of the top solution of generation six:</p>
<div style="text-align: center">
<object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/XnDqYsUgzKk"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/XnDqYsUgzKk" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object>
</div>
<p>If you&#8217;re feeling adventurous, you can try your hand at Wallace yourself:</p>
<div style="text-align: center">
<strong><a href="http://www.kuliniewicz.org/wallace/downloads/wallace-0.99.1.tar.gz">Download Wallace 0.99.1 (717 KB)</a></strong>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2007/02/26/wallace-0991-released/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>About Smegging Time (or, Wallace 0.99.0 is out!)</title>
		<link>http://www.kuliniewicz.org/blog/archives/2006/11/19/about-smegging-time-or-wallace-0990-is-out/</link>
		<comments>http://www.kuliniewicz.org/blog/archives/2006/11/19/about-smegging-time-or-wallace-0990-is-out/#comments</comments>
		<pubDate>Sun, 19 Nov 2006 04:15:21 +0000</pubDate>
		<dc:creator>Paul Kuliniewicz</dc:creator>
				<category><![CDATA[Wallace]]></category>

		<guid isPermaLink="false">http://www.kuliniewicz.org/blog/archives/2006/11/19/about-smegging-time-or-wallace-0990-is-out/</guid>
		<description><![CDATA[I&#8217;ll let the following link speak for itself:

Download Wallace 0.99.0 (source tarball, 713 KB)

&#8230;
OK, maybe I can say a little more.
I&#8217;ve got Wallace, everyone&#8217;s favorite NES emulator for Linux with a genetic programming tool bolted on, worked into a sufficiently functional state to let the outside world play with it.  Thet there link will [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ll let the following link speak for itself:</p>
<div style="text-align: center">
<strong><a href="http://www.kuliniewicz.org/wallace/downloads/wallace-0.99.0.tar.gz">Download Wallace 0.99.0 (source tarball, 713 KB)</a></strong>
</div>
<p>&#8230;</p>
<p>OK, maybe I can say a <em>little</em> more.</p>
<p>I&#8217;ve got <a href="http://www.kuliniewicz.org/blog/archives/category/coding/wallace/">Wallace</a>, everyone&#8217;s favorite NES emulator for Linux with a genetic programming tool bolted on, worked into a sufficiently functional state to let the outside world play with it.  Thet there link will get you a copy of the source code, which you can do the usual &#8220;<tt>./configure</tt>, <tt>make</tt>, <tt>make install</tt>&#8221; thing on to get a working copy of it.</p>
<p>A couple <a href="http://en.wikipedia.org/wiki/Caveat_emptor">caveats</a> to keep in mind before diving in, though.  First, consider this a tech demo, or pre-alpha software at best, not a polished, finished product.  It&#8217;ll probably work OK if you don&#8217;t poke or prod it too hard, though if you want to crash it or send it into <a href="http://en.wikipedia.org/wiki/Undefined_behavior">undefined behavior</a> I can think of three ways off the top of my head to do so.  Also, I make no guarantees that this release will be compatible with future ones, so don&#8217;t come crying to me if the evolver you&#8217;ve been running for weeks stops working when 0.99.1 (or whatever) comes out.</p>
<p>And of course, I&#8217;ve only tested this on my laptop running <a href="http://www.debian.org/">Debian</a> <a href="http://www.debian.org/releases/unstable/">unstable</a>.  Getting it to run on some other Linux system <em>shouldn&#8217;t</em> be too hard.  With work you might even be able to get it working on some other platform GNOME has been ported to, but I wouldn&#8217;t bet too much on it.</p>
<p>Now that all that&#8217;s out of the way, what&#8217;s new since the <a href="http://www.kuliniewicz.org/blog/archives/2006/10/15/attack-of-the-underflow/">last status update</a>?  Plenty!  The VM that the candidate solutions run on is now register-based (loosely based on the <a href="http://en.wikipedia.org/wiki/MIPS_architecture">MIPS architecture</a>), so solutions only crash inside the VM if they try to divide by zero nowadays.  You can also save your progress in the evolver tool, it executes as quickly as possible (instead of at normal emulation speed), and you can watch and encode candidate solutions at your leisure.</p>
<p>So what does it take to get a little genetic programming action started?  Let&#8217;s say you wanted to generate something to play <a href="http://en.wikipedia.org/wiki/Dr._Mario_%28video_game%29">Dr. Mario</a> (since score is much more closely correlated with progress there than in Super Mario Bros.).  First, you tell the Evolver what ROM image to use and what the initial state will be &#8212; here, we pick a state slot that begins on Level 10 on High speed:</p>
<div style="text-align: center">
<img id="image601" src="http://www.kuliniewicz.org/blog/wp-content/uploads/2006/11/game.png" alt="Game tab on the Evolver" />
</div>
<p>Next, we define our fitness function by specifying a set of metrics to measure and how to modify them.  Here, our fitness will be the score plus the number of seconds before losing.  Note the number of conditions we look for for when to stop evaluating a solution: the virus count dropping to zero (win!), the Game Over screen (lose!), the Pause screen (programs don&#8217;t need breaks!), and the Main Menu screen (ever try hitting A+B+Select+Start?):</p>
<div style="text-align: center">
<img id="image602" src="http://www.kuliniewicz.org/blog/wp-content/uploads/2006/11/fitness.png" alt="Fitness tab on the Evolver" />
</div>
<p>Next, we specify how we&#8217;ll be breeding our solutions.  The Evolver has several knobs you can play with to control population size and how to generate new solutions from old ones.  Lots more are certainly possible.  For example, it&#8217;d be nice to control how important the fitness score is to surviving to the next generation &#8212; currently, the top <var>n</var> solutions make it and the rest are culled, instead of doing some random-by-weight sort of selection.  Here&#8217;s the somewhat arbitrary settings I chose:</p>
<div style="text-align: center">
<img id="image603" src="http://www.kuliniewicz.org/blog/wp-content/uploads/2006/11/breeding.png" alt="Breeding tab on the Evolver" />
</div>
<p>Now all that&#8217;s left to do is switch over to the last tab, hit that nice green Run button, and watch the magic happen.</p>
<div style="text-align: center">
<img id="image604" src="http://www.kuliniewicz.org/blog/wp-content/uploads/2006/11/population.png" alt="Population tab on the Evolver" />
</div>
<p>So, how well does this work in practice?  I haven&#8217;t done much intensive experimentation, but early results are encouraging.  In the first generation (which are all purely randomly generated), most of the solutions either crash before getting very far or don&#8217;t do anything, letting the pills just stack up in the middle until the reach the top.  A couple of solutions do exhibit slightly more interesting behavior, such as this one, which rotates like mad and shoves pills to the left as fast as it can:</p>
<blockquote style="text-align: center"><p>
<a href="http://www.kuliniewicz.org/videos/drmario-gen1-172"><img id="image605" src="http://www.kuliniewicz.org/blog/wp-content/uploads/2006/11/drmario-gen1-172.png" alt="Solution from Generation 1" /></a></p>
<p>The top performer from Generation 1, with a fitness of 16.  (660 KB, 16 seconds)
</p></blockquote>
<p>Over the first few generations, the solutions that crash quickly die off, and the ones that just let the pills fall in the middle flourish.  Then the ones that shove the pills to one side or another, buying a few more precious seconds and thus increased fitness, dominate.  And then, in Generation 6, an exciting development: the first solution to kill a virus!</p>
<blockquote style="text-align: center"><p>
<a href="http://www.kuliniewicz.org/videos/drmario-gen6-2403.ogg"><img id="image606" src="http://www.kuliniewicz.org/blog/wp-content/uploads/2006/11/drmario-gen6-2403.png" alt="Solution from Generation 6" /></a></p>
<p>The top performer from Generation 6, with a fitness of 309.  (383 KB, 9 seconds)
</p></blockquote>
<p>To be fair, that screenshot makes the solution look like it&#8217;s playing far more shrewdly than it really is.  The video tells the whole story: it&#8217;s just shoving pills to the right, but does it at <em>just</em> the right rate to line up the red sections of the first three pills with the red virus.</p>
<p>And if you think that&#8217;s neat, check out what happens in Generation 7:</p>
<blockquote style="text-align: center"><p>
<a href="http://www.kuliniewicz.org/videos/drmario-gen7-2876.ogg"><img id="image607" src="http://www.kuliniewicz.org/blog/wp-content/uploads/2006/11/drmario-gen7-2876.png" alt="Solution from Generation 7" /></a></p>
<p>The top performer from Generation 7, with a fitness of 916.  (700 KB, 16 seconds)
</p></blockquote>
<p>That solution pushes pills to the right <em>and</em> rotates them at just the right speed to knock out two virus with the first three pills.  It is interesting how the end result after three pills is the same as what <em>I&#8217;d</em> do if I were behind the controller.  I can&#8217;t help but wonder how an <a href="http://en.wikipedia.org/wiki/Intelligent_design">Intelligent Design</a> proponent (that is to say, a <a href="http://en.wikipedia.org/wiki/Creationism">creationist</a>) would distinguish whether I or a seventh-generation evolved computer program were playing, given that screenshot.</p>
<p>Anyway, the next couple generations don&#8217;t turn up anything with a higher fitness than that, and that&#8217;s the point where I stopped it so I could work on pushing out this release.  Nevertheless, Generation 9 did produce the longest-lived solution so far, clocking in at almost double the time any of its competitors does, and still managing to kill a virus along the way.</p>
<blockquote style="text-align: center"><p>
<a href="http://www.kuliniewicz.org/videos/drmario-gen9-3317.ogg"><img id="image608" src="http://www.kuliniewicz.org/blog/wp-content/uploads/2006/11/drmario-gen9-3317.png" alt="Solution from Generation 9" /></a></p>
<p>The longest-lived performer from Generation 9, with a fitness of 329.  (1.2 MB, 29 seconds)
</p></blockquote>
<p>Not too shabby for a couple hours of evolution on a 1.7 GHz <a href="http://en.wikipedia.org/wiki/Pentium_M">Pentium M</a>, eh?</p>
<p>After all that I bet you&#8217;re dying to try this out for yourself, so I&#8217;ll reiterate:</p>
<div style="text-align: center">
<strong><a href="http://www.kuliniewicz.org/wallace/downloads/wallace-0.99.0.tar.gz">Download Wallace 0.99.0 (source tarball, 713 KB)</a></strong>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.kuliniewicz.org/blog/archives/2006/11/19/about-smegging-time-or-wallace-0990-is-out/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
