<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Igor Ostrovsky Blogging</title>
	
	<link>http://igoro.com</link>
	<description>On programming, technology, and random things of interest</description>
	<lastBuildDate>Thu, 29 Oct 2009 20:51:43 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/igoro" type="application/rss+xml" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">igoro</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>RoboZZle hacked, and 100+ sites are still compromised</title>
		<link>http://igoro.com/archive/robozzle-hacked-and-100-sites-are-still-compromised/</link>
		<comments>http://igoro.com/archive/robozzle-hacked-and-100-sites-are-still-compromised/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 09:59:31 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://igoro.com/?p=328</guid>
		<description><![CDATA[
 Around two weeks ago, I found this email in my inbox, with the subject “Complaint about Robozzle”:
Hi Igor
Robozzle is really cute, I like it, but why on earth is it polluted with hundreds of invisible links to porn sites? From a guy like you I don&#8217;t expect to do such dirty things. pls remove [...]]]></description>
			<content:encoded><![CDATA[<p><!-- blockquote { border: 1px solid #d0d0d0 } --></p>
<p><img style="border-right-width: 0px; margin: 0px 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="j0434750" src="http://igoro.com/wordpress/wp-content/uploads/2009/10/j0434750.png" border="0" alt="j0434750" width="36" height="36" align="right" /> Around two weeks ago, I found this email in my inbox, with the subject “Complaint about Robozzle”:</p>
<blockquote><p>Hi Igor</p>
<p>Robozzle is really cute, I like it, but why on earth is it polluted with hundreds of invisible links to porn sites? From a guy like you I don&#8217;t expect to do such dirty things. pls remove them.</p>
<p>David</p></blockquote>
<p><span id="more-328"></span></p>
<p>Hoping for a simple explanation, I looked at the source of the <a href="http://robozzle.com/">RoboZZle</a> front page. And my heart sunk as I saw <strong>hundreds</strong> of spam links on the bottom:</p>
<blockquote><p>&lt;a href=&#8221;&lt;a hijacked site&gt;.com/files/cms/7/pornhud.com-20076.html&#8221;&gt;porn hud.com&lt;/a&gt;<br />
&lt;a href=&#8221;&lt;a hijacked site&gt;.com/files/cms/7/www.tube.com8-5852.html&#8221;&gt;www.tube.com 8&lt;/a&gt;<br />
…</p></blockquote>
<p>The links were inside a &lt;p&gt; tag with visibility set to “hidden”, so the links were only visible to search engines, not to human visitors.</p>
<p>I wondered if this affected how my site shows up in search engines. So, I searched for RoboZZle on Google (results in Bing or Yahoo! were not affected), and here is what I got:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="robozzle_bad" src="http://igoro.com/wordpress/wp-content/uploads/2009/10/robozzle_bad1.png" border="0" alt="robozzle_bad" width="563" height="103" /></p>
<p>Oh crap. This sucks. How did it happen?</p>
<h3>Site infestation</h3>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="j0438025" src="http://igoro.com/wordpress/wp-content/uploads/2009/10/j0438025.png" border="0" alt="j0438025" width="144" height="144" align="right" /></p>
<p>So what did the hackers do to my poor game? I looked around to find what has changed:</p>
<ol>
<li><strong>Planted links<br />
</strong>Multiple pages on my site have been modified to import a planted config.ini file. The config.ini file contained hundreds of fake links, and was updated every couple hours with a new set of links. The links all pointed to spammy content planted on another hijacked site.<br />
 </li>
<li><strong>Planted content</strong><br />
My site also contained thousands of small planted HTML files, similar to the spammy stuff that the planted links pointed to. An odd folder (something like http://robozzle.com/old/old2/) contained the HTML files, all with links to suspicious content, and all infested with spammy keywords.<br />
 </li>
<li><strong>Backdoor PHP scripts</strong><br />
And finally, my site also contained a couple of PHP backdoor scripts. If you visited a particular URL on the robozzle.com domain, you’d get a file manager that lets you upload, delete, and manage files on my site, no passwords needed. As I found out later, the hackers actually knew my FTP password so they didn’t need the backdoors, but they left the backdoors so that they can get in once I change my password.</li>
</ol>
<p>I carefully checked my site and removed all of this stuff. Even after I removed the PHP backdoors, the config.ini file continued to get updated until I changed my FTP password. From that point, I was pretty sure that the attackers somehow got my FTP password.</p>
<h3>Looking for other hijacked sites</h3>
<p>After cleaning up my site, one of the first things I did was notify the other compromised site, which hosted the planted content linked from my site.</p>
<p>I also wondered if more sites have been hacked in a similar way. I tried various online tools to find other sites that contain the same links that have been planted on my site.</p>
<p>I found a handful of hacked sites right away. The fact that the links change every few hours made the task more difficult, though. The newest links generally point to content that has not yet been crawled by search engines. But, there is a simple solution. By looking at older versions of several compromised sites in a service like Google Cache, I eventually found older links that lead me to many more hijacked sites.</p>
<p>After repeating the process for a couple hours, I ended up with a list of over a <strong>150 infected sites</strong>, including some fairly major sites. The larger sites generally removed the infestation quickly, though. Here are a few sites that haven’t cleaned up, despite the fact that I alerted them at least two weeks ago:</p>
<ul>
<li>bayonnenj.org – City of Bayonne, NJ</li>
<li>steinercollege.edu &#8211; Rudolf Steiner College</li>
<li>dillard.senategop.org &#8211; GOP Senator Kirk Dillard</li>
<li>egnc-ibm.gov.eg &#8211; Egypt-IBM Nanotechnology Research Center</li>
</ul>
<p style="color: #800000"><strong>Don’t go to these sites unless you know what you are doing. At the time of writing this post, these sites appear to be compromised, so they may well contain viruses or malware.</strong></p>
<p><strong>UPDATE:</strong> Most of the sites are suddenly not showing the links. My guess is that the hacker group distributed an empty config.ini file after this story became popular on reddit. I don&#8217;t believe that so many obscure sites on my list would be fixed over night when they have been infected for months before. Some sites still contain the planted links, but those seem to be the ones that haven&#8217;t been updating the links regularly. These are probably the sites that the hackers only have partial control over at this point (e.g., FTP password changed, but there is still a backdoor on the site somewhere). You should be able to view the planted links on all infected sites by looking at Google Cache.</p>
<p>I did my best to contact owners of as many hijacked sites as I could. Looking for contact information on that many sites – most of them not in English &#8211; is a time-consuming endeavor, though.</p>
<h3>Tools I used</h3>
<p>I found these tools useful when tracking down other sites that have been hijacked:</p>
<table border="0" cellspacing="0" cellpadding="2" width="667">
<tbody>
<tr>
<td width="161" valign="top"><a href="http://siteexplorer.search.yahoo.com/">Yahoo! Site Explorer</a></td>
<td width="504" valign="top">This is the best tool I found to search for sites that link to a particular URL. At least for my purposes, it worked much better than “link:” queries in Google.<br />
 </td>
</tr>
<tr>
<td width="161" valign="top"><a href="http://proxify.org/">Proxify</a></td>
<td width="504" valign="top">When visiting sites controlled by hackers, it is worthwhile to be cautious, since the site may be infested by malware. Proxify sends the request on your behalf, and in the Source mode, sends you the HTTP response as text. So, the infested site won’t see your IP address, and any HTML it sends back will not be rendered, just shown in text format.<br />
 </td>
</tr>
<tr>
<td width="161" valign="top">Web caches</td>
<td width="504" valign="top">As you probably know, all major search engines (Google, Bing, Yahoo!) let you view the version of the page cached by the service. This gives you a version of the page as it was a few days or weeks ago.<br />
 </td>
</tr>
</tbody>
</table>
<p> </p>
<h3>And how did I get hacked in the first place?</h3>
<p>Of course, I have been wondering about how the hackers got my FTP password in the first place. It wasn’t really guessable or discoverable by brute force, and I didn’t use the same password on other sites.</p>
<p>And then I got an email from my webhost, notifying me that FTP passwords <strong>may have</strong> been stolen due to a vulnerability. They tracked down the issue to a particular software package they use.</p>
<p>So, I assume that my password got stolen this way. If not, it is also possible that I logged into my site on a computer with a particular virus. <a href="http://blog.tigertech.net/posts/ftp-password-viruses/">Apparently</a>, that’s how many FTP passwords get stolen.</p>
<blockquote><p>If you liked this article, check out these ones:</p>
<p><a href="http://igoro.com/archive/human-heart-is-a-turing-machine-research-on-xbox-360-shows-wait-what/">Human heart is a Turing machine, research on XBox 360 shows. Wait, what?</a></p>
<p><a href="http://igoro.com/archive/numbers-that-cannot-be-computed/">Numbers that cannot be computed</a></p></blockquote>
<img src="http://feeds.feedburner.com/~r/igoro/~4/V83D6pgIH80" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/robozzle-hacked-and-100-sites-are-still-compromised/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Human heart is a Turing machine, research on XBox 360 shows. Wait, what?</title>
		<link>http://igoro.com/archive/human-heart-is-a-turing-machine-research-on-xbox-360-shows-wait-what/</link>
		<comments>http://igoro.com/archive/human-heart-is-a-turing-machine-research-on-xbox-360-shows-wait-what/#comments</comments>
		<pubDate>Thu, 24 Sep 2009 08:13:31 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[Cool Stuff]]></category>

		<guid isPermaLink="false">http://igoro.com/?p=285</guid>
		<description><![CDATA[Did you ever see one of those auto-generated random “academic papers” like this one? When I first saw the following title, my first thought was that it is a randomly-generated “paper”:
Implications of the Turing completeness of reaction-diffusion models, informed by GPGPU simulations on an XBox 360: Cardiac arrhythmias, re-entry and the Halting problem [PDF]
Turing completeness, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://commons.wikimedia.org/wiki/File:CoeurHumain.svg"><img style="margin: 0px 0px 10px 10px; display: inline; border: 0px;" title="211px-CoeurHumain_svg" src="http://robozzle.com/igoro/211px-CoeurHumain_svg.gif" border="0" alt="211px-CoeurHumain_svg" width="150" align="right" /></a>Did you ever see one of those auto-generated random “academic papers” like <a href="http://pdos.csail.mit.edu/scigen/rooter.pdf">this one</a>? When I first saw the following title, my first thought was that it is a randomly-generated “paper”:</p>
<p><a href="http://www.sciencedirect.com/science?_ob=ArticleURL&amp;_udi=B73G2-4WH2KVG-1&amp;_user=10&amp;_rdoc=1&amp;_fmt=&amp;_orig=search&amp;_sort=d&amp;_docanchor=&amp;view=c&amp;_searchStrId=1022400504&amp;_rerunOrigin=scholar.google&amp;_acct=C000050221&amp;_version=1&amp;_urlVersion=0&amp;_userid=10&amp;md5=979bc3e20f7e915c6cb32be391bc370d">Implications of the Turing completeness of reaction-diffusion models, informed by GPGPU simulations on an XBox 360: Cardiac arrhythmias, re-entry and the Halting problem</a> [<a href="http://research.microsoft.com/pubs/79271/turing.pdf">PDF</a>]</p>
<p>Turing completeness, cardiac arrhythmias, XBox 360… those things don’t seem to have much in common. But, I had my interest piqued. I looked up the paper and read through it. And, it turns out that not only is the paper serious, what it has to say is also quite interesting.</p>
<p><span id="more-285"></span></p>
<h3>Heart and logic circuits</h3>
<p>I had to take author’s word on the medical aspects of the article, since I know nothing about cardiology. Apparently, understanding of electrical signals between cells in a human heart is important for research into heart arrhythmias. Makes sense.</p>
<p>The important insight of the article is that a logic NOR gate can be simulated using electrical signals between heart cells. Constructing a NOR gate is a powerful result, because similarly to NAND, NOR is a universal logic gate. That means that all other logic gates like AND, OR and NOT can be built out of NORs:</p>
<p><span style="font-family: Courier New;"><span style="color: #0080ff;">NOT</span>(A)    = <span style="color: #0080ff;">NOR</span>(A, A)<br />
<span style="color: #0080ff;">OR</span>(A, B)  = <span style="color: #0080ff;">NOR</span>(<span style="color: #0080ff;">NOR</span>(A, B), <span style="color: #0080ff;">NOR</span>(A, B))<br />
<span style="color: #0080ff;">AND</span>(A, B) = </span><span style="font-family: Courier New;"><span style="color: #0080ff;">NOR</span>(<span style="color: #0080ff;">NOR</span>(A, A), <span style="color: #0080ff;">NOR</span>(B, B))</span></p>
<p>So, since you can simulate a NOR gate using cardiac cells, you can simulate an arbitrary logic circuit in heart tissue.</p>
<h3>Heart and Turing machines</h3>
<p>But, there has to be more to the story. The paper title mentioned Turing machines, and logic circuits are not Turing-complete. Halting problem doesn’t even make sense when applied to boolean expressions!</p>
<p>The missing part is the passage of time. See, a logic circuit is not Turing-complete. But, if you take a logic circuit with multiple inputs, the same number of outputs as inputs, and repeatedly apply the circuit over the results of the previous iteration, you get a Turing-complete system. This type of a system can be modeled with behavior of a heart tissue over a period of time.</p>
<p>The most intuitive explanation that I can think of is via <a href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Game of Life</a>. In the Game of Life, each cell dies, becomes alive or stays alive depending on how many live neighbors it had in the previous generation.  Here is one example of a Game of Life board in action:</p>
<p><a href="http://en.wikipedia.org/wiki/File:Gospers_glider_gun.gif"><img style="display: inline;" title="Gospers_glider_gun" src="http://robozzle.com/igoro/Gospers_glider_gun.gif" alt="Gospers_glider_gun" width="250" height="180" /></a> </p>
<p>Now, the important observation is that the Game of Life rules can be encoded using a logic circuit. For example, if the eight neighbors of a particular cell are represented as A, B … H, then the rule that the cell becomes alive if it has exactly three neighbors can be encoded as  ((A and B and C and not(D) and … and not(H)) or (A and B and not(C) and D and not(E) … and not(H)) or …). This expression will be combined with an OR together with the situations under which the cell remains alive, rather than becoming alive. This will be a pretty ugly logic circuit, but it should be clear that it can be constructed.</p>
<p>Since Game of Life is known to be Turing-complete, then an “iterated logic circuit” is also Turing-complete, and the behavior of cardiac tissue is … Turing-complete.</p>
<div style="border: black 1px solid; padding-bottom: 4px; background-color: #f6f6ff; padding-left: 4px; width: 600px; padding-right: 4px; margin-left: 10px;padding-top: 4px">Also read about <a href="http://igoro.com/archive/numbers-that-cannot-be-computed/">Numbers that cannot be computed</a> and&nbsp; <a title="Link to Self-printing Game of Life in C#" href="http://igoro.com/archive/self-printing-game-of-life-in-c/">Self-printing Game of Life in C#</a>.</div>
<h3>Why is this useful?</h3>
<p>Proving that a particular behavior of cardiac tissue is Turing-complete is a useful result because it shows that the cardiac tissue is in a certain sense “unpredictable”.</p>
<p>For example, since Game of Life is Turing-complete, the Halting problem applies. So, it is a proven fact that there is no general algorithm that can look at a particular Game of Life board and decide whether the movement will eventually stop or continue forever.</p>
<p>Similarly, there is no algorithm that can decide any of these properties for all Game-of-Life boards:</p>
<ul>
<li>Whether the board will ever reach a particular configuration</li>
<li>Whether the number of live cells will ever exceed X</li>
<li>Whether the game will ever enter a cycle</li>
<li>etc.</li>
</ul>
<p>Since the studied behavior of cardiac tissue is also Turing-complete, there is no general algorithm that can look at the state of cardiac tissue and decide whether the activity will ever stop, enter a regular pattern, achieve a particular configuration, etc. That is certainly a worthwhile result!</p>
<h3>What about the XBox?</h3>
<p><a href="http://commons.wikimedia.org/wiki/File:Xbox_360.jpg"><img style="margin: 0px 0px 10px 10px; display: inline; border: 0px;" title="367px-Xbox_360" src="http://robozzle.com/igoro/367pxXbox_360.jpg" border="0" alt="367px-Xbox_360" width="147" height="240" align="right" /></a>Constructing a NOR gate out of cardiac cells is computationally intensive, and the researcher used a GPU in an XBox 360 for that task.</p>
<p>However, the paper doesn’t conclusively show that using an XBox was a real benefit. The paper says that a C++ implementation that was originally “designed more for ease of expansion […] than for speed” ran slower on an XBox 360 CPU than an “unoptimized” shader-based implementation on an XBox 360 GPU. Comparing implementations not designed for speed is unconvincing. If the goal was to speed up the computation, why not first try to optimize the original code instead of porting it to shaders, which is undoubtedly a much more difficult task?</p>
<p>Also, the article doesn’t say how did XBox 360 CPU compare against an ordinary x86 machine, or against say a CUDA-based implementation on a common NVidia card. So, the paper doesn’t come close to showing that the researchers gained much by coding against the XBox 360 GPU, rather than following the current state-of-the-art approaches.</p>
<p>But, it is still a cool paper, and adding XBox 360 into the picture certainly attracted attention. The paper was reported in press, with titles such as these:</p>
<ul>
<li><a href="http://www.time.com/time/health/article/0,8599,1925332,00.html">How Xbox Can Help Fight Heart Disease</a> [time.com].</li>
<li><a href="http://www.techshout.com/science/2009/16/study-parallel-processor-computing-of-xbox-chip-could-save-thousands/">Parallel processor computing of XBox chip could save thousands</a> [techshout.com].</li>
</ul>
<p>And, if it weren’t for the sensational articles, I wouldn’t have found out about the paper at all, so I guess I shouldn’t complain.</p>
<img src="http://feeds.feedburner.com/~r/igoro/~4/wwnFShSaqow" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/human-heart-is-a-turing-machine-research-on-xbox-360-shows-wait-what/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Program like a Quake developer</title>
		<link>http://igoro.com/archive/program-like-a-quake-developer/</link>
		<comments>http://igoro.com/archive/program-like-a-quake-developer/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 06:22:52 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[Algorithms]]></category>

		<guid isPermaLink="false">http://igoro.com/?p=192</guid>
		<description><![CDATA[Not many developers have the insights of Michael Abrash. He is a game developer with decades of experience building commercial games, including a game you may recognize as &#34;Quake&#34;. His Graphics Programming Black Book is years old, but much of it is just as interesting as it was at the time of writing. And, the [...]]]></description>
			<content:encoded><![CDATA[<p>Not many developers have the insights of Michael Abrash. He is a game developer with decades of experience building commercial games, including a game you may recognize as &quot;Quake&quot;. His Graphics Programming Black Book is years old, but much of it is just as interesting as it was at the time of writing. And, the entire book is available <a href="http://www.gamedev.net/reference/articles/article1698.asp">online</a>, for free.</p>
<p>The book consists of 70 chapters on optimization, graphics, and assembly programming. The entire book is insightful and interesting, but my favorite chapters are these:</p>
<ul>
<li><a href="http://downloads.gamedev.net/pdf/gpbb/gpbb1.pdf">The Best Optimizer Is between Your Ears</a>      </li>
<li><a href="http://downloads.gamedev.net/pdf/gpbb/gpbb16.pdf">There Ain’t No Such Thing as the Fastest Code</a>      </li>
<li>Optimizing for <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb11.pdf">286 and 386</a>, <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb12.pdf">486</a> (<a href="http://downloads.gamedev.net/pdf/gpbb/gpbb13.pdf">continued</a>), and <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb19.pdf">Pentium</a> (continued <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb20.pdf">here</a> and <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb21.pdf">here</a>).       </li>
<li>Algorithms for fast drawing of <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb35.pdf">lines</a>, <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb42.pdf">anti-aliased lines</a>, <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb38.pdf">polygons</a>, <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb39.pdf">fast convex polygons</a>, and <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb50.pdf">3d objects</a> (<a href="http://downloads.gamedev.net/pdf/gpbb/gpbb51.pdf">continued</a>)      </li>
<li>Quake’s <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb64.pdf">visible-surface determination</a>, <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb65.pdf">3D clipping</a>, <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb66.pdf">hidden-surface removal</a>, <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb67.pdf">span sorting</a>, <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb68.pdf">lighting</a>, <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb69.pdf">surface caching</a> and <a href="http://downloads.gamedev.net/pdf/gpbb/gpbb70.pdf">post-mortem</a>.</li>
</ul>
<p>Enjoy! Again, the entire book is accessible here: <a href="http://www.gamedev.net/reference/articles/article1698.asp">Graphics Programming Black Book</a>.</p>
<img src="http://feeds.feedburner.com/~r/igoro/~4/bRhvhwUIG50" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/program-like-a-quake-developer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Efficient auto-complete with a ternary search tree</title>
		<link>http://igoro.com/archive/efficient-auto-complete-with-a-ternary-search-tree/</link>
		<comments>http://igoro.com/archive/efficient-auto-complete-with-a-ternary-search-tree/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 00:27:54 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[Algorithms]]></category>

		<guid isPermaLink="false">http://igoro.com/?p=177</guid>
		<description><![CDATA[
	pre.code {
		margin-left: 40px;
	}
Over the past couple of years, auto-complete has popped up all over the web. Facebook, YouTube, Google, Bing, MSDN, LinkedIn and lots of other websites all try to complete your phrase as soon as you start typing.
Auto-complete definitely makes for a nice user experience, but it can be a challenge to implement efficiently. [...]]]></description>
			<content:encoded><![CDATA[<style>
<p>	pre.code {
		margin-left: 40px;
	}</style>
<p>Over the past couple of years, auto-complete has popped up all over the web. Facebook, YouTube, Google, Bing, MSDN, LinkedIn and lots of other websites all try to complete your phrase as soon as you start typing.</p>
<p>Auto-complete definitely makes for a nice user experience, but it can be a challenge to implement efficiently. In many cases, an efficient implementation requires the use of interesting algorithms and data structures. In this blog post, I will describe one simple data structure that can be used to implement auto-complete: a ternary search tree.</p>
<h3>Trie: simple but space-inefficient</h3>
<p> <span id="more-177"></span>
<p>Before discussing ternary search trees, let&#8217;s take a look at a simple data structure that supports a fast auto-complete lookup but needs too much memory: a <em>trie</em>. A trie is a tree-like data structure in which each node contains an array of pointers, one pointer for each character in the alphabet. Starting at the root node, we can trace a word by following pointers corresponding to the letters in the target word.</p>
<p>Each node could be implemented like this in C#:</p>
<pre class="code"><span style="color: blue">class </span><span style="color: #2b91af">TrieNode
</span>{
    <span style="color: blue">public const int </span>ALPHABET_SIZE = 26;
    <span style="color: blue">public </span><span style="color: #2b91af">TrieNode</span>[] m_pointers = <span style="color: blue">new </span><span style="color: #2b91af">TrieNode</span>[ALPHABET_SIZE];
    <span style="color: blue">public bool </span>m_endsString = <span style="color: blue">false</span>;
}</pre>
<p>Here is a trie that stores words AB, ABBA, ABCD, and BCD. Nodes that terminate words are marked yellow:</p>
<p>&#160;</p>
<p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="545" alt="gif_1" src="http://igoro.com/wordpress/wp-content/uploads/2009/08/gif-1.gif" width="577" border="0" /></p>
<p>&#160;</p>
<p>Implementing auto complete using a trie is easy. We simply trace pointers to get to a node that represents the string the user entered. By exploring the trie from that node down, we can enumerate all strings that complete user&#8217;s input.</p>
<p>But, a trie has a major problem that you can see in the diagram above. The diagram only fits on the page because the trie only supports four letters {A,B,C,D}. If we needed to support all 26 English letters, each node would have to store 26 pointers. And, if we need to support international characters, punctuation, or distinguish between lowercase and uppercase characters, the memory usage grows becomes untenable.</p>
<p>Our problem has to do with the memory taken up by all the null pointers stored in the node arrays. We could consider using a different data structure in each node, such as a hash map. However, managing thousands and thousands of hash maps is generally not a good idea, so let’s take a look at a better solution.</p>
<h3>Ternary search tree to the rescue</h3>
<p>A ternary tree is a data structure that solves the memory problem of tries in a more clever way. To avoid the memory occupied by unnecessary pointers, each trie node is represented as a tree-within-a-tree rather than as an array. Each non-null pointer in the trie node gets its own node in a ternary search tree.</p>
<p>For example, the trie from the example above would be represented in the following way as a ternary search tree:</p>
<p><img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="375" alt="image" src="http://igoro.com/wordpress/wp-content/uploads/2009/09/image.png" width="183" border="0" /></p>
<p>The ternary search tree contains three types of arrows. First, there are arrows that correspond to arrows in the corresponding trie, shown as dashed down-arrows. Traversing a down-arrow corresponds to “matching” the character from which the arrow starts. The left- and right- arrow are traversed when the current character does not match the desired character at the current position. We take the left-arrow if the character we are looking for is alphabetically before the character in the current node, and the right-arrow in the opposite case.</p>
<p>For example, green arrows show how we’d confirm that the ternary tree contains string ABBA:</p>
<p>&#160;<img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="375" alt="image" src="http://igoro.com/wordpress/wp-content/uploads/2009/09/image1.png" width="183" border="0" /></p>
<p>And this is how we’d find that the ternary string does not contain string ABD:</p>
<p><img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="375" alt="image" src="http://igoro.com/wordpress/wp-content/uploads/2009/09/image2.png" width="183" border="0" />&#160;</p>
<h3>Ternary search tree on a server</h3>
<p>On the web, a significant chunk of the auto-complete work has to be done by the server. Often, the set of possible completions is large, so it is usually not a good idea to download all of it to the client. Instead, the ternary tree is stored on the server, and the client will send prefix queries to the server.</p>
<p>The client will send a query for words starting with “bin” to the server:</p>
<p>&#160; <img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="218" alt="image" src="http://igoro.com/wordpress/wp-content/uploads/2009/09/image3.png" width="639" border="0" /></p>
<p>And the server responds with a list of possible words:</p>
<p><img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="218" alt="image" src="http://igoro.com/wordpress/wp-content/uploads/2009/09/image4.png" width="452" border="0" />&#160;</p>
<h3>Implementation</h3>
<p>Here is a simple ternary search tree implementation in C#:</p>
<pre class="code"><span style="color: blue">public </span><span style="color: blue">class </span><span style="color: #2b91af">TernaryTree
</span>{
    <span style="color: blue">private </span><span style="color: #2b91af">Node </span>m_root = <span style="color: blue">null</span>;

    <span style="color: blue">private void </span>Add(<span style="color: blue">string </span>s, <span style="color: blue">int </span>pos, <span style="color: blue">ref </span><span style="color: #2b91af">Node </span>node)
    {
        <span style="color: blue">if </span>(node == <span style="color: blue">null</span>) { node = <span style="color: blue">new </span><span style="color: #2b91af">Node</span>(s[pos], <span style="color: blue">false</span>); }

        <span style="color: blue">if </span>(s[pos] &lt; node.m_char) { Add(s, pos, <span style="color: blue">ref </span>node.m_left); }
        <span style="color: blue">else if </span>(s[pos] &gt; node.m_char) { Add(s, pos, <span style="color: blue">ref </span>node.m_right); }
        <span style="color: blue">else
        </span>{
            <span style="color: blue">if </span>(pos + 1 == s.Length) { node.m_wordEnd = <span style="color: blue">true</span>; }
            <span style="color: blue">else </span>{ Add(s, pos + 1, <span style="color: blue">ref </span>node.m_center); }
        }
    }

    <span style="color: blue">public void </span>Add(<span style="color: blue">string </span>s)
    {
        <span style="color: blue">if </span>(s == <span style="color: blue">null </span>|| s == <span style="color: #a31515">&quot;&quot;</span>) <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentException</span>();

        Add(s, 0, <span style="color: blue">ref </span>m_root);
    }

    <span style="color: blue">public bool </span>Contains(<span style="color: blue">string </span>s)
    {
        <span style="color: blue">if </span>(s == <span style="color: blue">null </span>|| s == <span style="color: #a31515">&quot;&quot;</span>) <span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentException</span>();

        <span style="color: blue">int </span>pos = 0;
        <span style="color: #2b91af">Node </span>node = m_root;
        <span style="color: blue">while </span>(node != <span style="color: blue">null</span>)
        {
            <span style="color: blue">int </span>cmp = s[pos] - node.m_char;
            <span style="color: blue">if </span>(s[pos] &lt; node.m_char) { node = node.m_left; }
            <span style="color: blue">else if </span>(s[pos] &gt; node.m_char) { node = node.m_right; }
            <span style="color: blue">else
            </span>{
                <span style="color: blue">if </span>(++pos == s.Length) <span style="color: blue">return </span>node.m_wordEnd;
                node = node.m_center;
            }
        }

        <span style="color: blue">return false</span>;
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><strong></strong></p>
<p>And here is the Node class:</p>
<pre class="code"><span style="color: blue">class </span><span style="color: #2b91af">Node
</span>{
    <span style="color: blue">internal char </span>m_char;
    <span style="color: blue">internal </span><span style="color: #2b91af">Node </span>m_left, m_center, m_right;
    <span style="color: blue">internal bool </span>m_wordEnd;

    <span style="color: blue">public </span>Node(<span style="color: blue">char </span>ch, <span style="color: blue">bool </span>wordEnd)
    {
        m_char = ch;
        m_wordEnd = wordEnd;
    }
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<h3>Remarks</h3>
<p>For best performance, strings should be inserted into the ternary tree in a random order. In particular, do not insert strings in the alphabetical order. Each mini-tree that corresponds to a single trie node would degenerate into a linked list, significantly increasing the cost of lookups. Of course, more complex self-balancing ternary trees can be implemented as well.</p>
<p>And, don’t use a fancier data structure than you have to. If you only have a relatively small set of candidate words (say on the order of hundreds) a brute-force search should be fast enough.</p>
<h3>Further reading</h3>
<p>Another article on tries is available on DDJ (careful, their implementation assumes that no word is a prefix of another):</p>
<p><a title="http://www.ddj.com/windows/184410528" href="http://www.ddj.com/windows/184410528">http://www.ddj.com/windows/184410528</a></p>
<p>If you like this article, also check out these posts on my blog:</p>
<ul>
<li><a href="http://igoro.com/archive/skip-lists-are-fascinating/">Skip lists are fascinating!</a> </li>
<li><a href="http://igoro.com/archive/numbers-that-cannot-be-computed/">Numbers that cannot be computed</a> </li>
<li><a href="http://igoro.com/archive/quicksort-killer/">Quicksort killer</a> </li>
</ul>
<img src="http://feeds.feedburner.com/~r/igoro/~4/il6UsbF_unM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/efficient-auto-complete-with-a-ternary-search-tree/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>7 tips for extending browser functionality to Silverlight apps</title>
		<link>http://igoro.com/archive/7-tips-for-extending-browser-functionality-to-silverlight-apps/</link>
		<comments>http://igoro.com/archive/7-tips-for-extending-browser-functionality-to-silverlight-apps/#comments</comments>
		<pubDate>Mon, 01 Jun 2009 07:52:06 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[Misc]]></category>
		<category><![CDATA[Silverlight]]></category>

		<guid isPermaLink="false">http://igoro.com/?p=164</guid>
		<description><![CDATA[Silverlight 2 is an awesome platform for development of rich web applications. One issue to be aware of, though, is that some browser features do not extend into Silverlight apps. For example, the Back and Forward browser buttons do not always work as the user may expect with Silverlight apps. The set of browser features [...]]]></description>
			<content:encoded><![CDATA[<p>Silverlight 2 is an awesome platform for development of rich web applications. One issue to be aware of, though, is that some browser features do not extend into Silverlight apps. For example, the Back and Forward browser buttons do not always work as the user may expect with Silverlight apps. The set of browser features you&#8217;ll miss in Silverlight apps is pretty much identical to what you&#8217;d miss in Flash or AJAX, and some of them are about to be addressed in the Silverlight 3 release.</p>
<p>Let&#8217;s go over the affected browser features one by one, and discuss ways of getting them working in Silverlight apps.</p>
<h3>Feature 1: Bookmarking and deep linking</h3>
<p><span id="more-164"></span>Users like to be able to copy the link from the address bar, email it to a friend, bookmark it, or post it on Twitter or Facebook.</p>
<p>A Silverlight app will typically transition between different views without redirecting the user to a different URL. This makes the user experience smooth and polished. As an unfortunate consequence, a user that copies the URL from the address bar or bookmarks the page will not get a link to the current active view, but instead a link to the initial view of the app.</p>
<p>Thankfully, there is a solution in Silverlight. A Silverlight app can modify the &#8220;bookmark&#8221; section of the URL, which is the part of the URL following the # character. The app can update the URL each time the user transitions to a different view, and read the bookmark on startup. See <a href="http://silverlight.net/blogs/msnow/archive/2008/09/16/silverlight-tip-of-the-day-41-using-bookmarks-in-your-silverlight-application.aspx">this article</a> for details on how to implement this.</p>
<p>The <a href="http://www.silverlightshow.net/items/The-Silverlight-3-Navigation-Framework.aspx">Navigation Framework</a> feature in the upcoming Silverlight 3 release will provide an easy-to-use solution to this problem.</p>
<h3>Feature 2: Search engine discoverability</h3>
<p>If your Silverlight app links to another page, that link is invisible to search engines. As a result, pages on your site that cannot be reached via traditional HTML links will likely not get listed in search results.</p>
<p>The solution is simple: list all pages on your site in an XML document called a Sitemap. Host the Sitemap on your site, and submit the Sitemap link to search engines. Once you do that, the search engines should include all pages on your site in their indexes.</p>
<p>For details, see the <a href="http://en.wikipedia.org/wiki/Google_Sitemaps">Wikipedia article on Sitemaps</a>.</p>
<h3>Feature 3: Back and Forward browser buttons</h3>
<p>The Back and Forward browser buttons do not work in Silverlight apps. Switching to a different view in a Silverlight app does not insert a bookmark into the browser history, so the user can&#8217;t go to the previous view by clicking the Back button.</p>
<p>The problem is similar to the bookmarking issue (Feature 1), except that the solution is more complicated. If the Silverlight app modifies the bookmark part of the URL, the previous bookmark does not get recorded in the browser history, so the user still cannot use the Back button to return to the previous view.</p>
<p>It is in fact possible to get the Back and Forward buttons working. As of SP1 3.5, ASP.NET exposes a History Control that simplifies the solution significantly (see <a href="http://blog.webjak.net/2008/09/08/control-silverlight-by-using-browser-back-and-foward-buttons/">Control Silverlight by Using Browser Back and Forward Buttons</a>). There is a variety of solutions available online in case you are not using ASP.NET 3.5 SP1, but beware that they typically involve hacks that don&#8217;t necessarily work in all browsers.</p>
<p>Or, you can wait until Silverlight 3, because browser history is properly handled in the Navigation Framework.</p>
<h3>Feature 4: Support of external tools (translation, accessibility, &#8230;)</h3>
<p>Automated translation, special browsers for people with disabilities, automated RSS aggregating&#8230; these are just some examples of useful tools that consume web content. These tools typically process HTML, but don&#8217;t peek inside Silverlight applications.</p>
<p>Since HTML is the standard representation of online documents, consider whether it would make sense to expose a simplified version of your content as a simple HTML page, in addition to your Silverlight application.</p>
<h3>Feature 5: Printing</h3>
<p>Silverlight does not currently have much support for printing. In Internet Explorer 7, Silverlight applications show up on the printout, but in Firefox or Safary they do not.</p>
<p>So, a Firefox or Safari user will not be able to print out the information displayed by your Silverlight application (at least not without taking screenshots, etc).</p>
<p>If you need to support printing, you can try two different solution approaches. If you only need to print content that can be represented using HTML (e.g., no Silverlight-generated charts and such), see <a href="http://jonas.follesoe.no/PrintingInSilverlight2UsingCSSAndASPNETAJAX4.aspx">this solution</a>. An alternate approach is to <a href="http://blog.galasoft.ch/archive/2008/10/10/converting-and-customizing-xaml-to-png-with-server-side-wpf.aspx">convert XAML to an image format on the server</a>.</p>
<h3>Feature 6: Open link in new tab</h3>
<p>There doesn&#8217;t seem to be a very good way to implement the &#8216;Open link in new tab&#8217; feature in Silverlight. You can use a HyperlinkButton with a Target set to _blank, which seems to open a new tab in Firefox and a new Window in IE 7. But that still won&#8217;t allow the user to choose whether to open the page in the same or different tab/window.</p>
<p>If you are committed enough, you can probably implement a HyperlinkButton with a context menu allowing the user to open the link in a new tab/window. Right-clicking is not directly supported in Silverlight, but <a href="http://silverlight.net/blogs/msnow/archive/2008/07/01/tip-of-the-day-14-how-to-right-click-on-a-silverlight-application.aspx">workarounds do exist</a>.</p>
<p>Or, use hyperlinks sparingly in Silverlight apps.</p>
<h3>Feature 7: Find on this page</h3>
<p>I use the &#8216;Find on this page&#8217; feature (CTRL+F) extensively when browsing the web. But, content inside Silverlight apps is not searched by the browser.</p>
<p>A mitigation is to carefully design the app UI in a way that minimizes the user&#8217;s need to search. Data should be sortable and searchable in various ways, and important information should be shown prominently (e.g., the user&#8217;s own position on a scoreboard should be highlighted).</p>
<p>These are all good practices regardless of your development platform, but unavailability of the &#8216;Find on this page&#8217; feature makes them even more important.</p>
<h3>Conclusion</h3>
<p>Hopefully you&#8217;ll find these points helpful when designing your next Silverlight application. If you have other tips on extending browser features into Silverlight apps, let me know in the comments!</p>
<img src="http://feeds.feedburner.com/~r/igoro/~4/lyYbeDhNFKs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/7-tips-for-extending-browser-functionality-to-silverlight-apps/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>My YouTube debut: a RoboZZle demo video</title>
		<link>http://igoro.com/archive/my-youtube-debut-a-robozzle-demo-video/</link>
		<comments>http://igoro.com/archive/my-youtube-debut-a-robozzle-demo-video/#comments</comments>
		<pubDate>Fri, 01 May 2009 08:53:39 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[RoboZZle]]></category>

		<guid isPermaLink="false">http://igoro.com/?p=155</guid>
		<description><![CDATA[It took significantly longer than I expected, but the RoboZZle demo video is finally on YouTube.
The video made the reddit front page, so you can read the usual mixture of insightful, funny, and outright insane comments on the reddit page and the YouTube page.
My favorite funny comment is this one:

And finally, this is the video:

]]></description>
			<content:encoded><![CDATA[<p>It took significantly longer than I expected, but the RoboZZle demo video is finally on YouTube.</p>
<p>The video made the reddit front page, so you can read the usual mixture of insightful, funny, and outright insane comments on the <a href="http://www.reddit.com/r/programming/comments/8gs5j/demo_video_of_robot_programming_game_with_user/">reddit page</a> and the <a href="http://www.youtube.com/watch?v=MmqBVWi_Pc0">YouTube page</a>.</p>
<p>My favorite funny comment is this one:<br />
<img class="alignnone size-full wp-image-159" style="border: 2px solid gray" title="silverlight_tinfoilhat1" src="http://igoro.com/wordpress/wp-content/uploads/2009/05/silverlight_tinfoilhat1.png" alt="silverlight_tinfoilhat1" width="630" height="159" /></p>
<p>And finally, this is the video:<br />
<object width="640" height="505" data="http://www.youtube.com/v/MmqBVWi_Pc0&amp;hl=en&amp;fs=1&amp;rel=0" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/MmqBVWi_Pc0&amp;hl=en&amp;fs=1&amp;rel=0" /><param name="allowfullscreen" value="true" /></object></p>
<img src="http://feeds.feedburner.com/~r/igoro/~4/D0JOcGRpUlo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/my-youtube-debut-a-robozzle-demo-video/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Precomputed view: A cool and useful SQL pattern</title>
		<link>http://igoro.com/archive/precomputed-view-a-cool-and-useful-sql-pattern/</link>
		<comments>http://igoro.com/archive/precomputed-view-a-cool-and-useful-sql-pattern/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 08:55:17 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[Misc]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://igoro.com/archive/precomputed-view-a-cool-and-useful-sql-pattern/</guid>
		<description><![CDATA[In database terminology, a view is a named query that typically aggregates data from multiple tables. When using views, it is important to remember that querying a view will evaluate the query that defines the view. Repeated evaluation of the view &#8211; say from within a nested query &#8211; may seriously impact or even kill [...]]]></description>
			<content:encoded><![CDATA[<p>In database terminology, a view is a named query that typically aggregates data from multiple tables. When using views, it is important to remember that querying a view will evaluate the query that defines the view. Repeated evaluation of the view &#8211; say from within a nested query &#8211; may seriously impact or even kill the performance of your application.</p>
<p>One solution to this performance problem is to use a &#8220;precomputed view&#8221;. Unlike an ordinary view, a precomputed view is stored in a table rather than computed on demand. When data in one of the aggregated tables changes, the update operation also updates the precomputed view table.</p>
<p><span id="more-137"></span></p>
<p>A great thing about precomputed views is that they can be implemented fully in SQL. Any code that accesses the database sees a precomputed view as a regular table. Also, if you have an existing regular view, you can change it into a precomputed view without having to modify any code that queries the view.</p>
<p>To explain the precomputed view pattern, let&#8217;s look at an example loosely inspired by the <a href="http://reddit.com/">reddit</a> social news site. Users submit articles to reddit and the articles receive up and down votes from other users. User&#8217;s &#8220;karma&#8221; is computed as a sum of votes on positively-voted articles submitted by the user.</p>
<p>To store the reddit data, you can store users in one table, articles in another table, and votes (+1 or -1) from users on articles in a third table:</p>
<p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="251" alt="image" src="/wordpress/wp-content/uploads/2009/04/image.png" width="513" border="0"> </p>
<p>Now, say that we want to find the top 10 users with highest karma. To compute a user&#8217;s karma, we need to sum up the scores of all articles submitted by the user. And to compute each article score, we need to aggregate the votes for that article. It should be clear that this query is going to be very expensive, no matter how much you tune and optimize it.</p>
<p>Views could be used to factor the complex query into simpler pieces, but not to decrease its overall cost:</p>
<p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="410" alt="image" src="/wordpress/wp-content/uploads/2009/04/image1.png" width="513" border="0">&nbsp;</p>
<p>It is easy to find the top 10 users, simply by querying User_View. Unfortunately, if the database contains millions and millions of votes, the query will take a long time to run. The query will have to group all votes by article, group all articles by user, and then pick the top users. Imagine the impact on performance if you wanted to show the top users on every page of your web app!</p>
<p>However, by changing the views into precomputed views, we can make the query for top users cheap:</p>
<p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="425" alt="image" src="/wordpress/wp-content/uploads/2009/04/image2.png" width="572" border="0">&nbsp; </p>
<p>Let&#8217;s walk through the conversion of Article_View to a precomputed view. First, we&#8217;ll create a table for the precomputed view:
<pre class="code"><span style="color: blue">    CREATE TABLE </span>Article_PView<span style="color: gray">(
        </span>ArticleId <span style="color: blue">int </span><span style="color: gray">NOT NULL,
        </span>Title <span style="color: blue">varchar</span><span style="color: gray">(</span>40<span style="color: gray">) NOT NULL,
        </span>Url <span style="color: blue">varchar</span><span style="color: gray">(</span>250<span style="color: gray">) NOT NULL,
        </span>VoteSum <span style="color: blue">int </span><span style="color: gray">NOT NULL,
    )
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Second, we&#8217;ll need two triggers. This trigger inserts a row into Article_PView whenever a new row is inserted into the Article table:
<pre class="code"><span style="color: blue">    CREATE TRIGGER </span>TRG_ArticleInsert
        <span style="color: blue">ON  </span>Article
        <span style="color: blue">AFTER INSERT
    AS
    BEGIN
        SET NOCOUNT ON</span><span style="color: gray">;

        </span><span style="color: blue">INSERT INTO </span>Article_PView <span style="color: gray">(</span>ArticleId<span style="color: gray">, </span>Title<span style="color: gray">, </span>Url<span style="color: gray">, </span>VoteSum<span style="color: gray">)
        </span><span style="color: blue">SELECT </span>Id <span style="color: blue">As </span>ArticleId<span style="color: gray">, </span>Title<span style="color: gray">, </span>Url<span style="color: gray">, </span>0
        <span style="color: blue">FROM </span>Inserted
<span style="color: blue">    END</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>And this trigger recomputes a row in Article_PView whenever a vote is inserted, updated or deleted:
<pre class="code"><span style="color: blue">    CREATE TRIGGER </span>TRG_Vote
        <span style="color: blue">ON  </span>Vote
        <span style="color: blue">AFTER INSERT</span><span style="color: gray">, </span><span style="color: blue">UPDATE</span><span style="color: gray">, </span><span style="color: blue">DELETE
    AS
    BEGIN
        SET NOCOUNT ON</span><span style="color: gray">;

        </span><span style="color: blue">WITH </span>articleIds<span style="color: gray">(</span>ArticleId<span style="color: gray">) </span><span style="color: blue">As
        </span><span style="color: gray">(
            </span><span style="color: blue">SELECT </span>ArticleId <span style="color: blue">From </span>Inserted
            <span style="color: blue">UNION
            SELECT </span>ArticleId <span style="color: blue">From </span>Deleted
        <span style="color: gray">)
        </span><span style="color: blue">UPDATE </span>Article_PView
            <span style="color: blue">SET </span>VoteSum <span style="color: gray">= (
                </span><span style="color: blue">SELECT </span><span style="color: magenta">SUM</span><span style="color: gray">(</span>Vote<span style="color: gray">) </span><span style="color: blue">FROM </span>Vote
                <span style="color: blue">WHERE </span>Article_PView<span style="color: gray">.</span>ArticleId <span style="color: gray">= </span>articleIds<span style="color: gray">.</span>ArticleId<span style="color: gray">)
        </span><span style="color: blue">FROM </span>articleIds
        <span style="color: blue">WHERE </span>Article_PView<span style="color: gray">.</span>ArticleId <span style="color: gray">= </span>articleIds<span style="color: gray">.</span>ArticleId
<span style="color: blue">    END</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>And finally, we&#8217;ll populate the precomputed view with data that is already in the database:
<pre class="code"><span style="color: blue">    INSERT INTO </span>Article_PView <span style="color: gray">(</span>ArticleId<span style="color: gray">, </span>Title<span style="color: gray">, </span>Url<span style="color: gray">, </span>VoteSum<span style="color: gray">)
</span><span style="color: blue">    SELECT </span>Article<span style="color: gray">.</span>Id<span style="color: gray">, </span>Title<span style="color: gray">, </span>Url<span style="color: gray">, </span><span style="color: magenta">ISNULL</span><span style="color: gray">((</span><span style="color: blue">SELECT </span><span style="color: magenta">SUM</span><span style="color: gray">(</span>vote<span style="color: gray">) </span><span style="color: blue">FROM </span>Vote <span style="color: blue">WHERE </span>ArticleId <span style="color: gray">= </span>Article<span style="color: gray">.</span>Id<span style="color: gray">), </span>0<span style="color: gray">)
</span><span style="color: blue">    FROM </span>Article</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Article_PView precomputed view is now ready, and User_PView can be created in a similar fashion. </p>
<p><strong>Remarks</strong> </p>
<p>Note that my example assumes articles never get removed or updated. Adding support for that functionality is straightforward: you&#8217;ll need to extend the TRG_ArticleInsert trigger to also handle updates and deletes. This will be very similar to what TRG_Vote does, but I left it out from the sample for simplicity.
</p>
<p>There are several interesting variations of how Article_PView could be implemented. In the implementation above, the trigger aggregates the votes for an article each time someone votes on it. If you want to avoid this cost, you can change the trigger so that it only adjusts the article score instead of recomputing it. For example, if a vote was updated from -1 to +1, the trigger would add 2 to the score of the article. Avoiding concurrency issues may be tricky with that approach, though.</p>
<p>Another interesting variation is adding the VoteSum column to the Article table instead of creating a separate table. Choose the approach that better fits your table design.</p>
<p>Hope you find this pattern useful!</p>
<img src="http://feeds.feedburner.com/~r/igoro/~4/k8LgfH3U2NY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/precomputed-view-a-cool-and-useful-sql-pattern/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Choose expression: proposal for a revolutionary C# construct</title>
		<link>http://igoro.com/archive/choose-expression-proposal-for-a-revolutionary-c-construct/</link>
		<comments>http://igoro.com/archive/choose-expression-proposal-for-a-revolutionary-c-construct/#comments</comments>
		<pubDate>Wed, 01 Apr 2009 09:04:36 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Algorithms]]></category>

		<guid isPermaLink="false">http://igoro.com/?p=122</guid>
		<description><![CDATA[Notice that this post was published on April 1, 2009.
For decades, computer science students have been taught that so-called NP-hard problems do not have known efficient solutions. These problems include the infamous Travelling salesman problem, subset sum, 3SAT, and many more.
But &#8211; as is often the case &#8211; where theoretical Computer Science failed, sound software [...]]]></description>
			<content:encoded><![CDATA[<p><span style="color: #ff0000;">Notice that this post was published on <strong>April 1</strong>, 2009.</span></p>
<p>For decades, computer science students have been taught that so-called NP-hard problems do not have known efficient solutions. These problems include the infamous <a href="http://en.wikipedia.org/wiki/Travelling_salesman_problem">Travelling salesman problem</a>, <a href="http://en.wikipedia.org/wiki/Subset_sum">subset sum</a>, <a href="http://en.wikipedia.org/wiki/3SAT">3SAT</a>, and many more.</p>
<p>But &#8211; as is often the case &#8211; where theoretical Computer Science failed, sound software engineering practices will succeed. By using loosely-coupled OOP, agile methodologies and the model-view-controller architectural pattern, I developed a solution that someone trapped in the world of formulas and big Ohs would never dream of.</p>
<p>Enough with the background, and let&#8217;s take a deep dive into the intriguing design.<br />
<span id="more-122"></span><br />
<strong>Introducing the choose expression</strong></p>
<p>As most other elegant designs, this one is very simple. My proposal calls for a choose expression with this syntax:</p>
<pre class="code">    <span style="color: blue">choose </span>{ boolean_expression1, boolean_expression2 }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Choose expression is basically the || operator, only with a slight twist. The semantics of the choose expression are similarly simple:</p>
<ol>
<li>If boolean_expression1 or boolean_expression2 will evaluate to true, the runtime will evaluate the true expression, but not the other expression. The return value of the choose expression will be true in this case.</li>
<li>If both expressions will evaluate to false, the runtime will evaluate neither expression. The return value of the choose expression is false in this case.</li>
</ol>
<p>Let&#8217;s look at a few simple usage examples:</p>
<pre class="code"><span style="color: blue">    bool </span>a = <span style="color: blue">choose </span>{
        1 == 2,
        1 &lt; 2
    };</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Variable a will be set to true, because the condition 1 &lt; 2 is true.</p>
<p>Here is another example:</p>
<pre class="code"><span style="color: blue">    bool </span>a = <span style="color: blue">choose </span>{
        ((<span style="color: #2b91af">Func</span>&lt;<span style="color: blue">bool</span>&gt;)(() =&gt; { <span style="color: #2b91af">Console</span>.WriteLine(<span style="color: #a31515">"Hello"</span>); <span style="color: blue">return false</span>; }))(),
        1 &lt; 2
    };</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>There is no point executing the first function, because it would return false anyways. So, this code sample does not print anything to screen. Instead, the choose expression will execute the second function. The second expression returns true, so variable a will be set to true.</p>
<p>And another simple one:</p>
<pre class="code"><span style="color: blue">    bool </span>a = <span style="color: blue">choose </span>{
        ((<span style="color: #2b91af">Func</span>&lt;<span style="color: blue">bool</span>&gt;)(() =&gt; { <span style="color: #2b91af">Console</span>.WriteLine(<span style="color: #a31515">"Hello1"</span>); <span style="color: blue">return false</span>; })(),
        ((<span style="color: #2b91af">Func</span>&lt;<span style="color: blue">bool</span>&gt;)(() =&gt; { <span style="color: #2b91af">Console</span>.WriteLine(<span style="color: #a31515">"Hello2"</span>); <span style="color: blue">return false</span>; })(),
    };</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>This code sample will not be print anything to screen either. It is obvious; why evaluate either of the two functions if they are going to return false anyways? This code simply assigns false to variable a.</p>
<p>Now, let&#8217;s cut to the chase, and use choose expressions to give an efficient implementation of an NP-hard problem. Let&#8217;s look at subset sum:</p>
<pre class="code"><span style="color: blue">    bool </span>SubsetSum(<span style="color: blue">int</span>[] arr)
    {
        <span style="color: blue">return </span>SubsetSumHelper(arr, 0, 0);
    }

<span style="color: blue">    bool </span>SubsetSumHelper(<span style="color: blue">int</span>[] arr, <span style="color: blue">int </span>index, <span style="color: blue">int </span>sumSoFar)
    {
        <span style="color: blue">if </span>(index == arr.Length)
        {
            <span style="color: blue">return </span>sumSoFar == 0;
        }

        <span style="color: blue">return </span><span style="color: blue">choose</span> {
            () =&gt; SubsetSumHelper(arr, index + 1, sumSoFar + arr[index]),
            () =&gt; SubsetSumHelper(arr, index + 1, sumSoFar)
        };
    }</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Yes, that&#8217;s right! An O(N) implementation of the subset sum problem. There you have it, computer scientists. You said it was impossible. If anyone at the University of British Columbia needs my mailing address to send me a refund check for my education, you can find my contact information in the margin.</p>
<p><strong>Under the hood of the choose expression</strong></p>
<p>After a couple hours of coding, I was able to develop a simple prototype. It works perfectly, but since it is only a prototype, I simplified my life a little bit by allowing choose to execute both functions. After all, I don&#8217;t have to slave through all the nitty-gritty details in the initial prototype, right? The performance of my implementation is not that great either, but I haven&#8217;t had the time to fire up the profiler so far. Perhaps I need to unroll a loop somewhere, or ensure that method calls are getting inlined optimally.</p>
<p>To further prove the feasibility of my design, I developed a <a href="http://en.wikipedia.org/wiki/Non-deterministic_turing_machine">non-deterministic Turing machine</a> construction that evaluates choose expressions extremely efficiently.</p>
<p>Non-deterministic Turing machines are known to be a good realistic abstraction of computing hardware; there was a study that proved that. To be exact, the study was only a moderate success. The researchers built a mechanical non-deterministic Turing machine that solved a Travelling Salesperson problem with 5 cities without a hitch. On the 6-city version of the problem, the experiment had to be abruptly interrupted after sprawling machine replicas filled up the room, and the head of one of the researchers got caught in a loop of tape.</p>
<p>So, it is clear that this design is sound. There may be performance issues in the first release, but they will improve as the technology matures. And once CPU manufacturers include a non-deterministic branching instruction in the instruction set, the cost of evaluating the choose expression will drop down to a couple of instructions.</p>
<p><strong>Summary</strong></p>
<p>I don&#8217;t know the detailed plans surrounding the C# language, but if there is a C# 4.1., I would like to see the choose expression included.</p>
<p>And the larger lesson of this post is simple: computer science is largely obsolete in today&#8217;s world of technology. Computer science says that this is impossible, that is impossible&#8230; As you just saw, anything is possible, so long as you have enough paper to print out all the UML diagrams.</p>
<img src="http://feeds.feedburner.com/~r/igoro/~4/47cNe1oefik" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/choose-expression-proposal-for-a-revolutionary-c-construct/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>The first month of my online game</title>
		<link>http://igoro.com/archive/the-first-month-of-my-online-game/</link>
		<comments>http://igoro.com/archive/the-first-month-of-my-online-game/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 10:47:15 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[RoboZZle]]></category>

		<guid isPermaLink="false">http://igoro.com/?p=112</guid>
		<description><![CDATA[It&#8217;s now been a month since I launched RoboZZle, so it is a good time to reflect on how things went so far. It has been a great experience, and the project took up all of my free time and then some.
For fun, I&#8217;ll discuss different aspects of RoboZZle and assign each a letter grade.
Game [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft" style="margin: 10px;" src="http://igoro.com/wordpress/wp-content/uploads/2009/03/robozzle_image.png" alt="" align="left" />It&#8217;s now been a month since I <a href="http://igoro.com/archive/my-hobby-project-a-social-puzzle-game-developed-in-silverlight/">launched</a> <a href="http://robozzle.com/">RoboZZle</a>, so it is a good time to reflect on how things went so far. It has been a great experience, and the project took up all of my free time and then some.</p>
<p>For fun, I&#8217;ll discuss different aspects of RoboZZle and assign each a letter grade.</p>
<p><strong>Game Addictiveness: A</strong><br />
<span id="more-112"></span><br />
Let&#8217;s start with the positive. RoboZZle has shown to be an addictive game, at least for a certain audience. There is a core group of players that log in regularly, solve puzzles, participate in discussions, design puzzles, propose improvements, and so forth.</p>
<p>A great illustration of my point is a quote from player <a href="http://robozzle.com/user.aspx?name=recursive">recursive</a> after finally cracking a long unsolved <a href="http://robozzle.com/puzzle.aspx?id=102">puzzle</a> designed by <a href="http://robozzle.com/user.aspx?name=evko">evko</a>:</p>
<blockquote><p>This level is amazing.</p>
<p>I spent about 6 hours solving this one. It took me a while to realize that every movement had to be saved on a stack. Then I developed diagrams, models, and a logical structure around it. And eventually stumbled my way to the solution logically. But it all seems so intuitively obvious now.</p>
<p>This is the best level I&#8217;ve solved so far. Bravo.</p></blockquote>
<p>RoboZZle players have contributed in a variety of ways:</p>
<ul>
<li><a href="http://robozzle.com/user.aspx?name=aalku">aalku</a> contributed articles to a number of sections of the <a href="http://robozzle.com/wiki/">wiki</a> (still in an early stage).</li>
<li><a href="http://robozzle.com/user.aspx?name=evko">evko</a> is a brilliant puzzle designer who created 42 puzzles, many of them amazingly clever and innovative.</li>
<li><a href="http://robozzle.com/user.aspx?name=hr0nix">hr0nix</a> implemented an <a href="http://code.google.com/p/robozzlesolver/">automated solver</a> for simpler RoboZZle puzzles.</li>
<li><a href="http://robozzle.com/user.aspx?name=life96">life96</a> made a number of helpful suggestions, and investigated the CPU usage of the game.</li>
<li><a href="http://robozzle.com/user.aspx?name=stingray">stingray</a> blogged about RoboZZle. The article <a href="http://www.genericerror.com/blog/2009/02/27/CanGamesTeachYouToProgram.aspx">Can Games Teach You To Program?</a> got popular on reddit.</li>
<li><a href="http://robozzle.com/user.aspx?name=recursive">recursive</a> has an amazingly deep understanding of the game, and discovered shortest known solution for nearly all puzzles.</li>
</ul>
<p>Finally, I really like this comment left by player <a href="http://robozzle.com/user.aspx?name=spikeless">spikeless</a> the day that RoboZZle launched:</p>
<blockquote><p>Brilliant game! It has seriously impacted productivity in our development team leaving nothing to be heard but frustrated curses and elated ‘Yesss’s.</p></blockquote>
<p>For addictiveness, I give RoboZZle a shameless A.</p>
<p><strong>Features: B</strong></p>
<p>My approach has been to do the minimal set of features I can get away with (but no less), and then grow the game from there. Otherwise, I would still be only 50% done; or more likely, I&#8217;d have given up a long time ago.</p>
<p>Since the game launched, I&#8217;ve been furiously adding features, in part driven by user feedback, and in part based on what I think will make the game work better.</p>
<p>I added <a href="http://robozzle.com/forums">forums</a>, <a href="http://robozzle.com/blog/?p=9">RSS feed for puzzles</a>, <a href="http://robozzle.com/wiki">wiki</a>, <a href="http://robozzle.com/forums">scoreboard for shortest solutions</a>, <a href="http://robozzle.com/blog/?p=14">a stepping debugger for solutions</a>, <a href="http://robozzle.com/forums/thread.aspx?id=168">a new game mode</a>, and lots more.</p>
<p>I give RoboZZle a B here because there are so many more things that I want to do with the game. I can already tell that this will keep me busy for a good while. <img src='http://igoro.com/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><strong>Code Quality: B-</strong></p>
<p>This section is about bugs! Similarly to features, I tried to make things &#8220;good enough&#8221;, and then deploy. Otherwise, I would never get anything done.</p>
<p>Most of the time, this worked fine. Only once a new feature introduced a major bug that impacted the game play for a lot of users. That time, the robot would sometimes seriously misbehave, e.g. continuing its path even though it should have died by falling off a tile.</p>
<p>Except for this one instance, most bugs have been minor issues that most players won&#8217;t run into. There are a few minor blemishes still present in the game, but I&#8217;m working my way through them.</p>
<p>So, it seems appropriate that RoboZZle gets a B- for quality.</p>
<p><strong>Incoming Traffic: C+</strong></p>
<p>Hmm&#8230; incoming traffic. While the loyalty of visitors seems to be great, the incoming traffic numbers aren&#8217;t quite as impressive. This table gives a quick summary:</p>
<table border="0" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td width="286" valign="top">Visits</td>
<td width="112" valign="top">23,000</td>
</tr>
<tr>
<td width="286" valign="top">Absolute Unique Visitors</td>
<td width="112" valign="top">12,754</td>
</tr>
<tr>
<td width="286" valign="top">Registered Players</td>
<td width="112" valign="top">1,379</td>
</tr>
<tr>
<td width="286" valign="top">Registered Players with 10+ puzzles solved</td>
<td width="112" valign="top">877</td>
</tr>
</tbody>
</table>
<p>23,000 visits is nothing to sneeze at, but I&#8217;ve seen similar numbers for  a blog post that took me a weekend to write. (In all fairness, most of those visitors probably spent less than a second &#8220;reading&#8221; my blog post.)</p>
<p>Here are the main sources of incoming traffic for robozzle.com:</p>
<table border="0" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td width="200" valign="top"><strong>Domain</strong></td>
<td width="200" valign="top"><strong>Visits</strong></td>
</tr>
<tr>
<td width="200" valign="top"><a href="http://silverlight.net/">silverlight.net</a></td>
<td width="200" valign="top">4,013</td>
</tr>
<tr>
<td width="200" valign="top"><a href="http://habrahabr.ru">habrahabr.ru</a></td>
<td width="200" valign="top">1,826</td>
</tr>
<tr>
<td width="200" valign="top"><a href="http://google.com">google.com</a></td>
<td width="200" valign="top">1,366</td>
</tr>
<tr>
<td width="200" valign="top"><a href="http://dotnetkicks.com">dotnetkicks.com</a></td>
<td width="200" valign="top">839</td>
</tr>
<tr>
<td width="200" valign="top"><a href="http://genericerror.com">genericerror.com</a></td>
<td width="200" valign="top">779</td>
</tr>
<tr>
<td width="200" valign="top"><a href="http://bluebytesoftware.com">bluebytesoftware.com</a></td>
<td width="200" valign="top">348</td>
</tr>
</tbody>
</table>
<p>So, it&#8217;s silverlight.net, some popular Russian site, google, dotnetkicks, and two blogs (both recommended reading). Other than that, there are many sources that contribute a small number of visitors each.</p>
<p>I should be able to do better. A part of the problem is that most people still don&#8217;t have Silverlight installed, and Silverlight gaming is in its infancy. There are signs that this is about to improve, such as <a href="http://mashooo.com">http://mashooo.com</a>, <a href="http://silverarcade.com">http://silverarcade.com</a> and <a href="http://silverlightclub.com">http://silverlightclub.com</a>, so I&#8217;m keeping my fingers crossed.</p>
<p>The other part of the problem is that I need to learn how to better market RoboZZle and draw in visitors. This is a new territory for me, but I&#8217;m learning new things every day.</p>
<p>And that&#8217;s the main reason I&#8217;m working on RoboZZle, so it&#8217;s OK. <img src='http://igoro.com/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<img src="http://feeds.feedburner.com/~r/igoro/~4/hwTl7-yIcKI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/the-first-month-of-my-online-game/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>My hobby project: a social puzzle game developed in Silverlight</title>
		<link>http://igoro.com/archive/my-hobby-project-a-social-puzzle-game-developed-in-silverlight/</link>
		<comments>http://igoro.com/archive/my-hobby-project-a-social-puzzle-game-developed-in-silverlight/#comments</comments>
		<pubDate>Sun, 22 Feb 2009 05:07:12 +0000</pubDate>
		<dc:creator>Igor Ostrovsky</dc:creator>
				<category><![CDATA[RoboZZle]]></category>

		<guid isPermaLink="false">http://igoro.com/archive/my-hobby-project-a-social-puzzle-game-developed-in-silverlight/</guid>
		<description><![CDATA[After about 3 months of evening coding, the game that I&#8217;ve been working on is now live.
RoboZZle is an online puzzle game that challenges you to program a robot to pick up all stars on a game board. The game mechanics are simple, yet allow for a wide variety of challenges that call for very [...]]]></description>
			<content:encoded><![CDATA[<p>After about 3 months of evening coding, the game that I&#8217;ve been working on is now <a href="http://robozzle.com/">live</a>.</p>
<p><a href="http://robozzle.com/">RoboZZle</a> is an online puzzle game that challenges you to program a robot to pick up all stars on a game board. The game mechanics are simple, yet allow for a wide variety of challenges that call for very different solution approaches.</p>
<p>Here is an example of a solved RoboZZle puzzle, with the arrow edited-in to show the path of the robot:</p>
<p><span id="more-96"></span>
<p><a href="http://igoro.com/wordpress/wp-content/uploads/2009/02/robozzle-puzzle.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="179" alt="robozzle_puzzle" src="http://igoro.com/wordpress/wp-content/uploads/2009/02/robozzle-puzzle-thumb.jpg" width="244" border="0"></a> </p>
<p>&nbsp;</p>
<p>Since designing RoboZZle puzzles is as much fun as solving them, the game includes a tool to make puzzles yourself. After you create a puzzle, you submit it, and other players will get an opportunity to try to solve it.</p>
<p>In this screenshot, I am just about done designing a challenging puzzle:</p>
<p><a href="http://igoro.com/wordpress/wp-content/uploads/2009/02/robozzle-designer.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="147" alt="robozzle_designer" src="http://igoro.com/wordpress/wp-content/uploads/2009/02/robozzle-designer-thumb.jpg" width="244" border="0"></a> </p>
<p>&nbsp;</p>
<p>Players rate the difficulty of each puzzle, as well as vote whether they liked it or not. When looking for the next puzzle to solve, players can use the ratings to find cool puzzles with the difficulty that suits their current mood.</p>
<p>This screenshot shows the main RoboZZle page at <a href="http://robozzle.com">http://robozzle.com</a>:</p>
<p><a href="http://igoro.com/wordpress/wp-content/uploads/2009/02/robozzle-main.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="175" alt="robozzle_main" src="http://igoro.com/wordpress/wp-content/uploads/2009/02/robozzle-main-thumb.png" width="244" border="0"></a>&nbsp;</p>
<p>&nbsp;</p>
<p>Players can lookup their ranking, as well as statistics on all players and puzzles on the <a href="http://www.robozzle.com/scoreboard.aspx">statistics pages</a>.</p>
<p><a href="http://igoro.com/wordpress/wp-content/uploads/2009/02/robozzle-stats.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="197" alt="robozzle_stats" src="http://igoro.com/wordpress/wp-content/uploads/2009/02/robozzle-stats-thumb.jpg" width="244" border="0"></a>&nbsp;</p>
<p>&nbsp;</p>
<p>In a Web 2.0 fashion, RoboZZle is designed to be a user-driven, social experience. Please <a href="http://robozzle.com/">check it out</a>, install Silverlight if you need to (it is safe to install), and let me know how you like the game.</p>
<img src="http://feeds.feedburner.com/~r/igoro/~4/_HRXNfSv51E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://igoro.com/archive/my-hobby-project-a-social-puzzle-game-developed-in-silverlight/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
	</channel>
</rss>
