<?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/"
	>

<channel>
	<title>danvk.org &#187; boggle</title>
	<atom:link href="http://www.danvk.org/wp/category/boggle/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.danvk.org/wp</link>
	<description>Keepin' static like wool fabric since 2006</description>
	<lastBuildDate>Fri, 20 Jan 2012 23:05:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>A Few More Boggle Examples</title>
		<link>http://www.danvk.org/wp/2009-08-11/a-few-more-boggle-examples/</link>
		<comments>http://www.danvk.org/wp/2009-08-11/a-few-more-boggle-examples/#comments</comments>
		<pubDate>Wed, 12 Aug 2009 04:01:30 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=570</guid>
		<description><![CDATA[Hopefully the last boggle post for a while! I figured I should throw up a few more examples while I still have time left on my OmniGraffle trial. There are two main shortcomings to the max/no mark upper bound: It can&#8217;t keep track of which words it&#8217;s already found. It can&#8217;t keep track of which [...]]]></description>
			<content:encoded><![CDATA[<p>Hopefully the last boggle post for a while! I figured I should throw up a few more examples while I still have time left on my <a href="http://www.omnigroup.com/applications/OmniGraffle/">OmniGraffle</a> trial.</p>
<style type="text/css">
.board { text-align: center; border-collapse: collapse; }
.board tbody td { border: 1px solid black; border-collapse: collapse; padding: 4px 8px 4px 8px; }
.board tbody td { font-weight: bold; }
.notable { color: red; }
.change td { padding: 2px 5px 2px 5px; }
.mb { font-family: monospace; padding: 0px 4px 0px 4px; }
</style>
<p>There are two main shortcomings to the max/no mark upper bound:</p>
<ol>
<li>It can&#8217;t keep track of which words it&#8217;s already found.</li>
<li>It can&#8217;t keep track of which choices it&#8217;s made on each cell.</li>
</ol>
<p>These can both be fixed, but only by incurring great computational complexity. Remember the <a href="/wp/2009-08-08/breaking-3x3-boggle/">tradeoff</a> between the &#8220;tightness&#8221; of a bound and the difficulty of computing it?</p>
<p>Our first example:<br />
<center></p>
<table class="board">
<tr>
<td>t</td>
<td>i</td>
<td>.</td>
</tr>
<tr>
<td>{a,e}</td>
<td>.</td>
<td>.</td>
</tr>
<tr>
<td>r</td>
<td>.</td>
<td>.</td>
</tr>
</table>
<p></center></p>
<p>Let&#8217;s look at the search tree starting with the &#8220;t&#8221; cell. There are three possible words: &#8220;tar&#8221;, &#8220;tie&#8221; and &#8220;tier&#8221;. Here&#8217;s the search tree that max/no mark generates:</p>
<p><center><img src="http://www.danvk.org/wp/wp-content/uploads/2009/08/tar-tier.png" alt="tar-tier" title="tar-tier" width="383" height="489" class="aligncenter size-full wp-image-571" /></center></p>
<p>(I&#8217;m drawing the trees slightly differently than I did in the last post, to make the branching more explicit. Branches inside dotted lines come from multiple possibilities on a cell. Other branches result from the ordinary process of looking in different directions from a cell.)</p>
<p>In this example, max/no mark chooses the &#8220;a&#8221; when it gets to the &#8220;{a,e}&#8221; cell directly from the &#8220;t&#8221;. This makes sense, since it results in one point to the e&#8217;s zero. However, when it gets to the &#8220;{a,e}&#8221; cell through the &#8220;ti&#8221;, it chooses the &#8220;e&#8221;. This also makes sense, since it gets two points from the &#8220;e&#8221; (&#8220;tie&#8221; and &#8220;tier&#8221;) vs. zero from the &#8220;tia&#8221; prefix. By the time it makes this choice, it has no memory of choosing the &#8220;a&#8221; the last time it encountered this cell. If it did, since the &#8220;tie&#8221; prefix results in two points to the &#8220;ta&#8221; prefix&#8217;s one, it would make sense to go back and change that choice. But remembering this would require lots of expensive bookkeeping. It&#8217;s faster (but yields a looser bound) if we just accept the possibility that we&#8217;ll make different choices.</p>
<p>Example number 2 of max/no mark&#8217;s failings:<br />
<center></p>
<table class="board">
<tr>
<td>t</td>
<td>h</td>
<td>.</td>
</tr>
<tr>
<td>h</td>
<td>e</td>
<td>.</td>
</tr>
<tr>
<td>.</td>
<td>.</td>
<td>.</td>
</tr>
</table>
<p></center></p>
<p><center><img src="http://www.danvk.org/wp/wp-content/uploads/2009/08/the-the.png" alt="the-the" title="the-the" width="312" height="292" class="aligncenter size-full wp-image-575" /></center></p>
<p>The problem in this case is that max/no mark doesn&#8217;t remember which words it&#8217;s already found. At first glance, it seems like this problem would be easy to remedy. And it certainly would on this board, in which each cell only has a single possible letter. But if you think about a board with lots of choices, you&#8217;ll start to see why it&#8217;s best to just give up and accept a looser bound.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2009-08-11/a-few-more-boggle-examples/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Some max/no mark examples</title>
		<link>http://www.danvk.org/wp/2009-08-11/some-maxno-mark-examples/</link>
		<comments>http://www.danvk.org/wp/2009-08-11/some-maxno-mark-examples/#comments</comments>
		<pubDate>Tue, 11 Aug 2009 20:41:57 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=552</guid>
		<description><![CDATA[After the last post, several people mentioned that they were confused about how the &#8220;max/no mark&#8221; upper bound on the highest score in a class of Boggle boards worked. With some help from OmniGraffle, I&#8217;ve created some instructive examples. Here&#8217;s a class of boards: f {a,u} r . . e . . . The dots [...]]]></description>
			<content:encoded><![CDATA[<p>After the <a href="/wp/2009-08-08/breaking-3x3-boggle/">last post</a>, several people mentioned that they were confused about how the &#8220;max/no mark&#8221; upper bound on the highest score in a class of Boggle boards worked. With some help from <a href="http://www.omnigroup.com/applications/OmniGraffle/">OmniGraffle</a>, I&#8217;ve created some instructive examples.</p>
<p>Here&#8217;s a class of boards:</p>
<style type="text/css">
.board { text-align: center; border-collapse: collapse; }
.board tbody td { border: 1px solid black; border-collapse: collapse; padding: 4px 8px 4px 8px; }
.board tbody td { font-weight: bold; }
.notable { color: red; }
.change td { padding: 2px 5px 2px 5px; }
.mb { font-family: monospace; padding: 0px 4px 0px 4px; }
</style>
<p><center></p>
<table class="board">
<tr>
<td>f</td>
<td>{a,u}</td>
<td>r</td>
</tr>
<tr>
<td>.</td>
<td>.</td>
<td>e</td>
</tr>
<tr>
<td>.</td>
<td>.</td>
<td>.</td>
</tr>
</table>
<p></center></p>
<p>The dots mean &#8220;no letters here&#8221;. The class contains two different boards:</p>
<p><center></p>
<table>
<tr>
<td valign=top>
<table class="board">
<tr>
<td>f</td>
<td>a</td>
<td>r</td>
</tr>
<tr>
<td>.</td>
<td>.</td>
<td>e</td>
</tr>
<tr>
<td>.</td>
<td>.</td>
<td>.</td>
</tr>
</table>
<p><img src="http://www.danvk.org/wp/wp-content/uploads/2009/08/fare-score.png" alt="fare-score" title="fare-score" width="92" height="396" class="aligncenter size-full wp-image-555" />
</td>
<td width="30">&nbsp;</td>
<td valign=top>
<table class="board">
<tr>
<td>f</td>
<td>u</td>
<td>r</td>
</tr>
<tr>
<td>.</td>
<td>.</td>
<td>e</td>
</tr>
<tr>
<td>.</td>
<td>.</td>
<td>.</td>
</tr>
</table>
<p><img src="http://www.danvk.org/wp/wp-content/uploads/2009/08/fur-score.png" alt="fur-score" title="fur-score" width="108" height="292" class="aligncenter size-full wp-image-556" />
</td>
</tr>
</table>
<p></center></p>
<p>It contains two boards. The one with an &#8220;a&#8221; has two points worth of words on it, while the one with a &#8220;u&#8221; only has one. (We&#8217;re only looking at words starting with &#8216;f&#8217; here.)</p>
<p>The diagrams show that the solver starts with the &#8216;f&#8217; on each board and explores adjacent cells. When it finds a word, it scores it and passes the total score back up the depth-first search tree.</p>
<p>Here&#8217;s how the max/no mark bound sees that board class:<br />
<center><br />
<img src="http://www.danvk.org/wp/wp-content/uploads/2009/08/fare-fur-score.png" alt="fare-fur-score" title="fare-fur-score" width="269" height="397" class="aligncenter size-full wp-image-554" /><br />
</center></p>
<p>When it gets to the &#8220;{a,u}&#8221; cell, it tries both possible letters. The &#8220;a&#8221; tree brings back 2 points, whereas the &#8220;u&#8221; tree brings back 1 point. So it chooses &#8220;a&#8221; and counts two points. As it so happens, this is the score of the highest-scoring board. The sum/union bound would have added the 1 and the 2, resulting in an upper bound of 3. The max/no mark bound takes advantage of the fact that this cell can only be one of two possibilities, not both.</p>
<p>Now what if we throw a few more letters on:</p>
<p><center></p>
<table class="board">
<tr>
<td>f</td>
<td>{a,u}</td>
<td>r</td>
</tr>
<tr>
<td>z</td>
<td>.</td>
<td>e</td>
</tr>
<tr>
<td>z</td>
<td>y</td>
<td>.</td>
</tr>
</table>
<p></center></p>
<p>With the new letters, there are more points coming from the u:</p>
<p><center><br />
<img src="http://www.danvk.org/wp/wp-content/uploads/2009/08/fare-fur-fuzzy-score.png" alt="fare-fur-fuzzy-score" title="fare-fur-fuzzy-score" width="348" height="503" class="aligncenter size-full wp-image-553" /><br />
</center></p>
<p>The two points going through the &#8216;a&#8217; are dropped on the floor. sum/union would have resulting in a bound of 4+2. When there are lots of letter choices on every cell, you can see why max/no mark is a much tighter bound.</p>
<p>It&#8217;s important to note that there are two sources of branching in these search trees: (1) being able to go in multiple directions from a cell (i.e. f->u->r or z) and (2) having multiple choices on a cell (i.e. f->a or u). The max/no mark bound sums the scores resulting from choices in case (1) and takes the max of choices in case (2). The sum/union bound takes the sum in both cases.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2009-08-11/some-maxno-mark-examples/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Breaking 3&#215;3 Boggle</title>
		<link>http://www.danvk.org/wp/2009-08-08/breaking-3x3-boggle/</link>
		<comments>http://www.danvk.org/wp/2009-08-08/breaking-3x3-boggle/#comments</comments>
		<pubDate>Sat, 08 Aug 2009 17:35:04 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>
		<category><![CDATA[math]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=516</guid>
		<description><![CDATA[Why is finding the highest-scoring Boggle board so difficult? It&#8217;s because there are so many boards to consider: 2^72 for the 4&#215;4 case and 2^40 for the 3&#215;3 case. At 10,000 boards/second the former corresponds to about 2 billion years of compute time, and the latter just two years. Just enumerating all 2^72 boards would [...]]]></description>
			<content:encoded><![CDATA[<p>Why is finding the highest-scoring Boggle board so difficult? It&#8217;s because there are so many boards to consider: 2^72 for the 4&#215;4 case and 2^40 for the 3&#215;3 case. At <a href="http://www.danvk.org/wp/2007-02-10/one-last-boggle-boost/">10,000 boards/second</a> the former corresponds to about 2 billion years of compute time, and the latter just two years. Just enumerating all 2^72 boards would take over 100,000 years.</p>
<p>So we have to come up with a technique that doesn&#8217;t involve looking at every single board. And I&#8217;ve come up with just such a method! This is the &#8220;exciting news&#8221; I alluded to in the last post.</p>
<p>Here&#8217;s the general technique:</p>
<ol>
<li>Find a very high-scoring board (maybe <a href="http://www.danvk.org/wp/2009-02-19/sky-high-boggle-scores-with-simulated-annealing/">this way</a>)</li>
<li>Consider a large class of boards</li>
<li>Come up with an upper bound on the highest score achieved by any board in the class.</li>
<li>If it&#8217;s lower than the score in step #1, we can eliminate all the boards in the class. If it&#8217;s not, subdivide the class and repeat step #2 with each subclass.</li>
</ol>
<p><b>Classes of Boards</b><br />
By &#8220;class of boards&#8221;, I mean something like this:</p>
<style type="text/css">
.board { text-align: center; border-collapse: collapse; }
.board tbody td { border: 1px solid black; border-collapse: collapse; padding: 4px 8px 4px 8px; }
.board tbody td { font-weight: bold; }
.notable { color: red; }
.change td { padding: 2px 5px 2px 5px; }
.mb { font-family: monospace; padding: 0px 4px 0px 4px; }
</style>
<p><center></p>
<table class="board">
<tr>
<td>{a,e,i,o,u}</td>
<td>{a,e,i,o,u}</td>
<td>r</td>
</tr>
<tr>
<td>{b,c,d,f,g,h}</td>
<td>a</td>
<td>t</td>
</tr>
<tr>
<td>d</td>
<td>e</td>
<td>{r,s,t,v}</td>
</tr>
</table>
<p></center></p>
<p>The squares that contain a set of letters can take on <i>any</i> of those letters. So this board is part of that class:</p>
<p><center></p>
<table class="board">
<tr>
<td>a</td>
<td>i</td>
<td>r</td>
</tr>
<tr>
<td>d</td>
<td>a</td>
<td>t</td>
</tr>
<tr>
<td>d</td>
<td>e</td>
<td>s</td>
</tr>
<tfoot>
<tr>
<td colspan=3><a href="/boggle3.php?quick=airdatdes">189 points</a></td>
</tr>
</tfoot>
</table>
<p></center></p>
<p>and so is this:</p>
<p><center></p>
<table class="board">
<tr>
<td>o</td>
<td>u</td>
<td>r</td>
</tr>
<tr>
<td>f</td>
<td>a</td>
<td>t</td>
</tr>
<tr>
<td>d</td>
<td>e</td>
<td>t</td>
</tr>
<tfoot>
<tr>
<td colspan=3><a href="/boggle3.php?quick=ourfatdet">114 points</a></td>
</tr>
</tfoot>
</table>
<p></center></p>
<p>All told, there are 5 * 5 * 6 * 4 = 600 boards that are part of this class, each with its own score. Other fun classes of boards include &#8220;boards with only vowels&#8221; (1,953,125 members) and &#8220;boards with only consonants&#8221; (794,280,046,581 members).</p>
<p>Follow me past the fold for more&#8230;<br />
<span id="more-516"></span></p>
<p><b>Upper Bounds</b><br />
Now on to step #3 of the general technique: calculating an upper bound. This is going to be easier if we introduce some mathematical notation:</p>
<p><center></p>
<table>
<tr>
<td align=right><i>b</i></td>
<td>=</td>
<td>A boggle board</td>
</tr>
<tr>
<td align=right><i>Score(b)</i></td>
<td>=</td>
<td>sum of the scores of all the words contained on b</td>
</tr>
<tr>
<td align=right><i><b>B</b></i></td>
<td>=</td>
<td>a class of boards, i.e. <img src='http://s.wordpress.com/latex.php?latex=b%20%5Cin%20B&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='b \in B' title='b \in B' class='latex' /></td>
</tr>
<tr>
<td align=right><i>Score(<b>B</b>)</i></td>
<td>=</td>
<td><img src='http://s.wordpress.com/latex.php?latex=max%28%5C%7BScore%28b%29%20%7C%20b%20%5Cin%20B%5C%7D%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='max(\{Score(b) | b \in B\})' title='max(\{Score(b) | b \in B\})' class='latex' /></td>
</tr>
</table>
<p></center></p>
<p>An upper bound is a function <img src='http://s.wordpress.com/latex.php?latex=f%28B%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='f(B)' title='f(B)' class='latex' /> such that <img src='http://s.wordpress.com/latex.php?latex=f%28B%29%20%5Cgeq%20Score%28B%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='f(B) \geq Score(B)' title='f(B) \geq Score(B)' class='latex' />, i.e. <img src='http://s.wordpress.com/latex.php?latex=f%28B%29%20%5Cgeq%20Score%28b%29%20%5Cforall%20b%20%5Cin%20B&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='f(B) \geq Score(b) \forall b \in B' title='f(B) \geq Score(b) \forall b \in B' class='latex' />.</p>
<p>There&#8217;s one really easy upper bound: <img src='http://s.wordpress.com/latex.php?latex=Score%28B%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='Score(B)' title='Score(B)' class='latex' />! This just enumerates all the boards in the class B, scores each and takes the maximum score. It&#8217;s very expensive to compute for a large class of boards and hence not very practical. You and I both know that no board in containing only consonants has any points on it. We don&#8217;t need to enumerate through all 794 billion such boards to determine this.</p>
<p>With upper bounds, there&#8217;s a trade-off between how hard they are to compute and how &#8220;tight&#8221; they are, i.e. how closely they approximate <img src='http://s.wordpress.com/latex.php?latex=Score%28B%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='Score(B)' title='Score(B)' class='latex' />. <img src='http://s.wordpress.com/latex.php?latex=Score%28B%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='Score(B)' title='Score(B)' class='latex' /> is very tight but is hard to compute. At the other end of the spectrum, we know that all the words on a board are in the dictionary. So we could just sum up the scores of all the words in the dictionary and get a number, say 1,000,000. Then <img src='http://s.wordpress.com/latex.php?latex=f%28B%29%20%3D%201%2C000%2C000&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='f(B) = 1,000,000' title='f(B) = 1,000,000' class='latex' /> is an upper bound. It is very easy to compute, but is not very tight.</p>
<p>The trick is to hit some sort of sweet spot that strikes a good balance between &#8220;tightness&#8221; and ease of computation. Over the rest of this blog post, I&#8217;ll present two upper bounds that do this. Upper bounds have the nice property that if <img src='http://s.wordpress.com/latex.php?latex=f%28B%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='f(B)' title='f(B)' class='latex' /> and <img src='http://s.wordpress.com/latex.php?latex=g%28B%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='g(B)' title='g(B)' class='latex' /> are two upper bounds, then <img src='http://s.wordpress.com/latex.php?latex=h%28B%29%20%3D%20min%28f%28B%29%2C%20g%28B%29%29&#038;bg=ffffff&#038;fg=000000&#038;s=0' alt='h(B) = min(f(B), g(B))' title='h(B) = min(f(B), g(B))' class='latex' /> is also an upper bound. So by finding two bounds, we&#8217;ll get a third that&#8217;s better than either one alone.</p>
<p><b>sum/union</b><br />
The idea of this bound is to find all the words that can possibly occur in a class of boards. Since each word can only be found once, we can add the scores of all these words to get an upper bound.</p>
<p>To get the list of words, we use the same <a href="http://www.danvk.org/wp/2007-02-01/tries-the-perfect-data-structure/">depth-first search strategy</a> as we did to find words on a single board. The wrinkle is that, when we encounter a cell with multiple possible letters, we have to do a separate depth-first search for each.</p>
<p>At first glance, it doesn&#8217;t seem like this would be tractable for a board class like this one (alternating vowels and consonants):</p>
<p><center></p>
<table class="board">
<tr>
<td>{a,e,i,o,u}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{a,e,i,o,u}</td>
</tr>
<tr>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{a,e,i,o,u}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
</tr>
<tr>
<td>{a,e,i,o,u}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{a,e,i,o,u}</td>
</tr>
</table>
<p></center></p>
<p>In addition to the branching from going different directions on each square, there&#8217;s also a huge amount of branching from trying each letter on each square. But we&#8217;re saved by the same lesson we learned in <a href="http://www.danvk.org/wp/2007-01-30/boggle-3-succeed-by-not-being-stupid/">boggle post #3</a>: the dictionary is exceptionally effective at pruning thorny search trees. If we prune search trees like &#8216;bqu&#8217; that don&#8217;t begin words, then there doesn&#8217;t wind up being that much work to do.</p>
<p>We can find all possible words on the above board in just under 1 second. This is about 10,000 times slower than it takes to score a conventional board, but it&#8217;s certainly tractable. The resulting score is 195,944. Given that no board scores higher than 545 points, this is a wild overestimate. But at least it&#8217;s a better bound than a million!</p>
<p>This technique does especially well on boards like this one, which contains all consonants:</p>
<p><center></p>
<table class="board">
<tr>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
</tr>
<tr>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
</tr>
<tr>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
</tr>
</table>
<p></center></p>
<p>This takes 0.23 seconds to score and results in a bound of 208 points (it contains words like &#8216;crypt&#8217; and &#8216;gypsy&#8217;). We&#8217;ve already <a href="http://www.danvk.org/wp/2009-08-04/solving-boggle-by-taking-option-three/">found</a> a single board that has <a href="/boggle3.php?quick=perlatdes">545 points</a> on it. So we can eliminate this entire class of 794 billion boards. That&#8217;s a speed of over 3 trillion boards/second! Of course, this board class is not typical.</p>
<p>It&#8217;s also worth pointing out why this upper bound isn&#8217;t tight. Consider this class of boards:</p>
<p><center></p>
<table class="board">
<tr>
<td>{a,i}</td>
<td>r</td>
<td>z</td>
</tr>
<tr>
<td>f</td>
<td>z</td>
<td>z</td>
</tr>
<tr>
<td>z</td>
<td>z</td>
<td>z</td>
</tr>
</table>
<p></center></p>
<p>You can find both &#8220;fir&#8221; and &#8220;far&#8221; on boards in this class, but there aren&#8217;t any boards that contain <i>both</i>. So while each &#8220;fir and &#8220;far&#8221; contribute a point to the upper bound, they should only really contribute a single point. The sum/union bound doesn&#8217;t take into account the relationships between various letter choices. It&#8217;s the best trade-off between computability and &#8220;tightness&#8221; we&#8217;ve seen so far, but it&#8217;s not good enough to make the problem tractable.</p>
<p><b>max/no mark</b><br />
In the sum/union upper bound, we dealt with multiple possible letters on the same square by trying each and adding the resulting scores (taking care not to count any word twice). But why take the sum of all choices when we know that any given board can only take on one of the possibilities? It would result in a much better bound if we took the max of the scores resulting from each possible choice, rather than the sum. This is the idea behind the &#8220;max/no mark&#8221; bound.</p>
<p>This is a huge win over sum/union, especially when there are many squares containing many possible letters. It does have one major drawback, though. The sum/union bound took advantage of the fact that each word could only be found once. With the max/no mark bound, the bookkeeping for this becomes completely intractable. The words we find by making a choice on one square may affect the results of a choice somewhere else. We can&#8217;t make the choices independently. The optimal set of choices becomes an optimization problem in its own right.</p>
<p>Rather than deal with this, max/no mark just throws up its hands. This is what the &#8220;no mark&#8221; refers to. In the past, we&#8217;ve recorded the words we find by <a href="http://www.danvk.org/wp/2007-02-10/one-last-boggle-boost/">marking the Trie</a>. By not marking the Trie with found words, we accept that we&#8217;ll double-count words sometimes. But it still winds up being an excellent upper bound.</p>
<p>Lets try some of our previous examples:</p>
<p><center></p>
<table class="board">
<tr>
<td>{a,e,i,o,u}</td>
<td>{a,e,i,o,u}</td>
<td>r</td>
</tr>
<tr>
<td>{b,c,d,f,g,h}</td>
<td>a</td>
<td>t</td>
</tr>
<tr>
<td>d</td>
<td>e</td>
<td>{r,s,t,v}</td>
</tr>
<tfoot>
<tr>
<td colspan=3 align=center>sum/union: 2880</td>
</tr>
<tr>
<td colspan=3>max/no mark: 1307</td>
</tr>
</tfoot>
</table>
<p></center></p>
<p>Alternating vowels and consonants:</p>
<p><center></p>
<table class="board">
<tr>
<td>{a,e,i,o,u}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{a,e,i,o,u}</td>
</tr>
<tr>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{a,e,i,o,u}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
</tr>
<tr>
<td>{a,e,i,o,u}</td>
<td>{b-d,f-h,j-n,p-t,v-z}</td>
<td>{a,e,i,o,u}</td>
</tr>
<tfoot>
<tr>
<td colspan=3>sum/union: 195944</td>
</tr>
<tr>
<td colspan=3>max/no mark: 15692</td>
</tr>
</tfoot>
</table>
<p></center></p>
<p>A class that can be entirely eliminated:</p>
<p><center></p>
<table class="board">
<tr>
<td>{b,d,f,g,j,k,m,p,v,w,x,z}</td>
<td>a</td>
<td>{s,y}</td>
</tr>
<tr>
<td>{i,o,u}</td>
<td>y</td>
<td>a</td>
</tr>
<tr>
<td>{s,y}</td>
<td>{c,h,l,n,r,t}</td>
<td>{c,h,l,n,r,t}</td>
</tr>
<tfoot>
<tr>
<td colspan=3>sum/union: 2497</td>
</tr>
<tr>
<td colspan=3>max/no mark: 447</td>
</tr>
</tfoot>
</table>
<p></center></p>
<p>max/no mark isn&#8217;t always better than sum/union:</p>
<p><center></p>
<table class="board">
<tr>
<td>{b,d}</td>
<td>a</td>
<td>{b,d}</td>
</tr>
<tr>
<td>a</td>
<td>{b,d}</td>
<td>a</td>
</tr>
<tr>
<td>{b,d}</td>
<td>a</td>
<td>{b,d}</td>
</tr>
<tfoot>
<tr>
<td colspan=3>sum/union: 9</td>
</tr>
<tr>
<td colspan=3>max/no mark: 132</td>
</tr>
</tfoot>
</table>
<p></center></p>
<p>This is something of a worst-case because, while there are relatively few distinct words, there are many different ways to find them.</p>
<p><b>Putting it all together</b><br />
Our two bounds do well in different situations. max/no mark works best when there are lots of choices to be made on particular cells and there are relatively few ways to make any particular word. sum/union works best when there are lots of possibilities but relatively few distinct words. Putting them together results in a bound that&#8217;s good enough to find the best 3&#215;3 boggle board using the technique described at the beginning of this post.</p>
<p>Given an initial class of boards, we wind up with what I call a &#8220;breaking tree&#8221;. If the initial class has an upper bound less than 545 points, then we&#8217;re done. Otherwise, we pick a cell to split and try each possibility.</p>
<p>Here&#8217;s a relatively small breaking tree that results from running <a href="http://code.google.com/p/performance-boggle/source/browse/trunk/3x3/ibucket_breaker.cc">this program</a>:</p>
<pre>
$ ./3x3/ibucket_breaker --best_score 520 --break_class "bdfgjkmpvwxz a sy iou xyz aeiou sy chlnrt chlnrt"
(     0%) (0;1/1) bdfgjkmpvwxz a sy iou xyz aeiou sy chlnrt chlnrt (820, 77760 reps)
                            split cell 4 (xyz) Will evaluate 3 more boards...
(     0%)  (1;1/3) bdfgjkmpvwxz a sy iou x aeiou sy chlnrt chlnrt (475, 25920 reps)
(33.333%)  (1;2/3) bdfgjkmpvwxz a sy iou y aeiou sy chlnrt chlnrt (703, 25920 reps)
                            split cell 5 (aeiou) Will evaluate 5 more boards...
(33.333%)   (2;1/5) bdfgjkmpvwxz a sy iou y a sy chlnrt chlnrt (447, 5184 reps)
(    40%)   (2;2/5) bdfgjkmpvwxz a sy iou y e sy chlnrt chlnrt (524, 5184 reps)
                            split cell (iou) 3 Will evaluate 3 more boards...
(    40%)    (3;1/3) bdfgjkmpvwxz a sy i y e sy chlnrt chlnrt (346, 1728 reps)
(42.222%)    (3;2/3) bdfgjkmpvwxz a sy o y e sy chlnrt chlnrt (431, 1728 reps)
(44.444%)    (3;3/3) bdfgjkmpvwxz a sy u y e sy chlnrt chlnrt (339, 1728 reps)
(46.667%)   (2;3/5) bdfgjkmpvwxz a sy iou y i sy chlnrt chlnrt (378, 5184 reps)
(53.333%)   (2;4/5) bdfgjkmpvwxz a sy iou y o sy chlnrt chlnrt (423, 5184 reps)
(    60%)   (2;5/5) bdfgjkmpvwxz a sy iou y u sy chlnrt chlnrt (318, 5184 reps)
(66.667%)  (1;3/3) bdfgjkmpvwxz a sy iou z aeiou sy chlnrt chlnrt (509, 25920 reps)
</pre>
<p>The numbers in parentheses are the upper bounds. When they get below 520 (the parameter I set on the command line), a sub-class is fully broken.</p>
<p>Using this technique and the following partition of the 26 letters:</p>
<ul>
<li>bdfgjvwxz
<li>aeiou
<li>lnrsy
<li>chkmpt
</ul>
<p>I was able to go through all 262,144 (=4^9) board classes in about six hours on a single machine. This resulted in the boards I listed in the <a href="http://www.danvk.org/wp/2009-08-04/solving-boggle-by-taking-option-three/">last post</a>. Six hours is a big improvement over two years!</p>
<p>If that same factor (two years to six hours) held for the 4&#215;4 case, then we&#8217;d be down to 380 years of compute time to find the best 4&#215;4 boggle board. Or, equivalently, 138 days on 1000 machines. That&#8217;s still a lot. We&#8217;re not quite there yet, but we&#8217;re getting closer!</p>
<p>Code for the program that went through all possible board classes can be found <a href="http://code.google.com/p/performance-boggle/source/browse/trunk/#trunk/paper">here</a>. While <a href="http://ai.stanford.edu/~chuongdo/boggle/index.html">many</a> <a href="http://ankurdave.com/AnkurDaveExtendedEssay2009.pdf">people</a> have found high-scoring boards, I haven&#8217;t found any previous work on this upper bounding approach. So if you have any ideas/suggestions on how to improve the bound, they&#8217;re probably novel and useful!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2009-08-08/breaking-3x3-boggle/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Solving Boggle by Taking Option Three</title>
		<link>http://www.danvk.org/wp/2009-08-04/solving-boggle-by-taking-option-three/</link>
		<comments>http://www.danvk.org/wp/2009-08-04/solving-boggle-by-taking-option-three/#comments</comments>
		<pubDate>Wed, 05 Aug 2009 01:18:03 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=503</guid>
		<description><![CDATA[There is exciting news to report in the land of Boggle! Last we spoke about Boggle, we used Simulated Annealing to get at the question &#8220;what is the highest-scoring Boggle board?&#8221; We found a board with 3625 points on it this way. It would have been nice to say that it was the best of [...]]]></description>
			<content:encoded><![CDATA[<p>There is exciting news to report in the land of Boggle!</p>
<p>Last <a href="http://www.danvk.org/wp/2009-02-19/sky-high-boggle-scores-with-simulated-annealing/">we spoke</a> about Boggle, we used <a href="http://en.wikipedia.org/wiki/Simulated_Annealing">Simulated Annealing</a> to get at the question &#8220;what is the highest-scoring Boggle board?&#8221;</p>
<p>We found a board with <a href="/boggle.php?quick=perslatgsineters">3625 points</a> on it this way. It would have been nice to say that it was the best of all possible boards, but that would have been too rash. While it is a very good board and I have never seen a higher-scoring one, that doesn&#8217;t mean there isn&#8217;t one out there. Maybe I&#8217;ve just been looking in the wrong places.</p>
<p>To prove that the 3625-pointer is the best board, we&#8217;d need to show that every other board scores fewer points. In a previous post, I <a href="http://www.danvk.org/wp/2007-08-02/how-many-boggle-boards-are-there/">estimated</a> that there were 2^69 possible boggle boards. At <a href="http://www.danvk.org/wp/2007-02-10/one-last-boggle-boost/">10,000 boards/second</a>, this would take 1.9 billion years of compute time!</p>
<p>When you run up against a computationally intractable problem, there are a few standard ways to deal with it:</p>
<ol>
<li>Give up.</li>
<li>Come up with a brilliant new algorithm to solve the problem more quickly.</li>
<li>Solve a simpler problem.</li>
</ol>
<p>Option 1 is the easiest. Option 2 is the hardest. And option 3 is the compromise we&#8217;ll be taking for the next few danvk.org boggle posts. Our simpler problem today: 3&#215;3 boggle.</p>
<p>If we drop seven letters (4&#215;4 &#8211; 3&#215;3 = 7), we&#8217;re left with only 26^9 / 8 &cong; 2^39 boards to consider. If we can achieve 10,000 boards/sec, this would be just over two years&#8217; worth of computation. That&#8217;s still a lot, but it&#8217;s much more reasonable than 1.9 billion years!</p>
<p>I believe I have solved the 3&#215;3 boggle problem using an approach that is only slightly more clever than this. I used simulated annealing to find very high-scoring 3&#215;3 boards. This was the best one I found, along with its 4&#215;4 best board buddy:</p>
<style type="text/css">
.board { text-align: center; border-collapse: collapse; }
.board tbody td { border: 1px solid black; border-collapse: collapse; padding: 4px 8px 4px 8px; }
.board tbody td { font-weight: bold; }
.notable { color: red; }
.change td { padding: 2px 5px 2px 5px; }
.mb { font-family: monospace; padding: 0px 4px 0px 4px; }
</style>
<p><center><br />
<table>
<tr>
<td>
<p><center></p>
<table class="board">
<tr>
<td>p</td>
<td>e</td>
<td>r</td>
</tr>
<tr>
<td>l</td>
<td>a</td>
<td>t</td>
</tr>
<tr>
<td>d</td>
<td>e</td>
<td>s</td>
</tr>
<tfoot>
<tr>
<td colspan=4><a href="/boggle3.php?quick=perlatdes">545 points</a></td>
</tr>
</tfoot>
</table>
<p></center></p>
</td>
<td width=50>&nbsp;</td>
<td>
<p><center></p>
<table class="board">
<tr>
<td>p</td>
<td>e</td>
<td>r</td>
<td>s</td>
</tr>
<tr>
<td>l</td>
<td>a</td>
<td>t</td>
<td>g</td>
</tr>
<tr>
<td>s</td>
<td>i</td>
<td>n</td>
<td>e</td>
</tr>
<tr>
<td>t</td>
<td>e</td>
<td>r</td>
<td>s</td>
</tr>
<tfoot>
<tr>
<td colspan=4><a href="/boggle.php?quick=perslatgsineters">3625 points</a></td>
</tr>
</tfoot>
</table>
<p></center></p>
</tr>
</td>
</table>
<p></center></p>
<p>It&#8217;s worth noting that the optimal 3&#215;3 board has a 2&#215;3 region in common with the 3625 point 4&#215;4 board.</p>
<p>In the next post we&#8217;ll talk about how I showed that this board was higher-scoring than all 2^39 others in significantly less than two years (it took one day). As a teaser, I&#8217;ve included all the 3&#215;3 boards with more than 500 points worth of words below the fold.</p>
<p><span id="more-503"></span></p>
<p>I&#8217;ve made the boards fit on a single line by reading them like a book: left to right, then top to bottom.</p>
<table>
<tr>
<th>Board</th>
<th>Score</th>
</tr>
<tr>
<td>perlatdes</td>
<td><a href="/boggle3.php?quick=perlatdes">545</a></td>
</tr>
<tr>
<td>pelsartes</td>
<td><a href="/boggle3.php?quick=pelsartes">542</a></td>
</tr>
<tr>
<td>delratpes</td>
<td><a href="/boggle3.php?quick=delratpes">540</a></td>
</tr>
<tr>
<td>lepsartes</td>
<td><a href="/boggle3.php?quick=lepsartes">536</a></td>
</tr>
<tr>
<td>tepsarles</td>
<td><a href="/boggle3.php?quick=tepsarles">528</a></td>
</tr>
<tr>
<td>selratpes</td>
<td><a href="/boggle3.php?quick=selratpes">528</a></td>
</tr>
<tr>
<td>legsartes</td>
<td><a href="/boggle3.php?quick=legsartes">527</a></td>
</tr>
<tr>
<td>berlatdes</td>
<td><a href="/boggle3.php?quick=berlatdes">526</a></td>
</tr>
<tr>
<td>relsatpes</td>
<td><a href="/boggle3.php?quick=relsatpes">524</a></td>
</tr>
<tr>
<td>perlatces</td>
<td><a href="/boggle3.php?quick=perlatces">523</a></td>
</tr>
<tr>
<td>derlatpes</td>
<td><a href="/boggle3.php?quick=derlatpes">522</a></td>
</tr>
<tr>
<td>telsarpes</td>
<td><a href="/boggle3.php?quick=telsarpes">520</a></td>
</tr>
<tr>
<td>parletdes</td>
<td><a href="/boggle3.php?quick=parletdes">520</a></td>
</tr>
<tr>
<td>lersatpes</td>
<td><a href="/boggle3.php?quick=lersatpes">520</a></td>
</tr>
<tr>
<td>saltipres</td>
<td><a href="/boggle3.php?quick=saltipres">518</a></td>
</tr>
<tr>
<td>tepsarled</td>
<td><a href="/boggle3.php?quick=tepsarled">514</a></td>
</tr>
<tr>
<td>tegsarles</td>
<td><a href="/boggle3.php?quick=tegsarles">514</a></td>
</tr>
<tr>
<td>tedsalrep</td>
<td><a href="/boggle3.php?quick=tedsalrep">514</a></td>
</tr>
<tr>
<td>repsalted</td>
<td><a href="/boggle3.php?quick=repsalted">514</a></td>
</tr>
<tr>
<td>ledsartep</td>
<td><a href="/boggle3.php?quick=ledsartep">514</a></td>
</tr>
<tr>
<td>pelsatres</td>
<td><a href="/boggle3.php?quick=pelsatres">513</a></td>
</tr>
<tr>
<td>tegsarlep</td>
<td><a href="/boggle3.php?quick=tegsarlep">511</a></td>
</tr>
<tr>
<td>lepsarteg</td>
<td><a href="/boggle3.php?quick=lepsarteg">511</a></td>
</tr>
<tr>
<td>tapselres</td>
<td><a href="/boggle3.php?quick=tapselres">510</a></td>
</tr>
<tr>
<td>serlitpas</td>
<td><a href="/boggle3.php?quick=serlitpas">508</a></td>
</tr>
<tr>
<td>lecsartep</td>
<td><a href="/boggle3.php?quick=lecsartep">508</a></td>
</tr>
<tr>
<td>tedsarleg</td>
<td><a href="/boggle3.php?quick=tedsarleg">507</a></td>
</tr>
<tr>
<td>persatles</td>
<td><a href="/boggle3.php?quick=persatles">507</a></td>
</tr>
<tr>
<td>legsarted</td>
<td><a href="/boggle3.php?quick=legsarted">507</a></td>
</tr>
<tr>
<td>tepsarleg</td>
<td><a href="/boggle3.php?quick=tepsarleg">505</a></td>
</tr>
<tr>
<td>selratdes</td>
<td><a href="/boggle3.php?quick=selratdes">505</a></td>
</tr>
<tr>
<td>legsartep</td>
<td><a href="/boggle3.php?quick=legsartep">505</a></td>
</tr>
<tr>
<td>canretdes</td>
<td><a href="/boggle3.php?quick=canretdes">505</a></td>
</tr>
<tr>
<td>canretdes</td>
<td><a href="/boggle3.php?quick=canretdes">505</a></td>
</tr>
<tr>
<td>pinlatres</td>
<td><a href="/boggle3.php?quick=pinlatres">504</a></td>
</tr>
<tr>
<td>nirgatres</td>
<td><a href="/boggle3.php?quick=nirgatres">504</a></td>
</tr>
<tr>
<td>lecsartes</td>
<td><a href="/boggle3.php?quick=lecsartes">504</a></td>
</tr>
<tr>
<td>serlatpes</td>
<td><a href="/boggle3.php?quick=serlatpes">503</a></td>
</tr>
<tr>
<td>letrasdep</td>
<td><a href="/boggle3.php?quick=letrasdep">503</a></td>
</tr>
<tr>
<td>derlitpas</td>
<td><a href="/boggle3.php?quick=derlitpas">503</a></td>
</tr>
<tr>
<td>derlatbes</td>
<td><a href="/boggle3.php?quick=derlatbes">502</a></td>
</tr>
<tr>
<td>cerlatpes</td>
<td><a href="/boggle3.php?quick=cerlatpes">502</a></td>
</tr>
<tr>
<td>cerlatpes</td>
<td><a href="/boggle3.php?quick=cerlatpes">502</a></td>
</tr>
<tr>
<td>retgasnil</td>
<td><a href="/boggle3.php?quick=retgasnil">501</a></td>
</tr>
<tr>
<td>nilgasret</td>
<td><a href="/boggle3.php?quick=nilgasret">501</a></td>
</tr>
<tr>
<td>metparles</td>
<td><a href="/boggle3.php?quick=metparles">501</a></td>
</tr>
<tr>
<td>merpatles</td>
<td><a href="/boggle3.php?quick=merpatles">501</a></td>
</tr>
<tr>
<td>tedsarlep</td>
<td><a href="/boggle3.php?quick=tedsarlep">500</a></td>
</tr>
<tr>
<td>tapselred</td>
<td><a href="/boggle3.php?quick=tapselred">500</a></td>
</tr>
<tr>
<td>redseltap</td>
<td><a href="/boggle3.php?quick=redseltap">500</a></td>
</tr>
<tr>
<td>pecsartes</td>
<td><a href="/boggle3.php?quick=pecsartes">500</a></td>
</tr>
<tr>
<td>lepsarted</td>
<td><a href="/boggle3.php?quick=lepsarted">500</a></td>
</tr>
</table>
<p>As always, this using the <a href="http://everything2.com/title/ENABLE+word+list">Enable2K word list</a>. Code can be found <a href="http://code.google.com/p/performance-boggle/source/browse/#svn/trunk/3x3">here</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2009-08-04/solving-boggle-by-taking-option-three/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sky-High Boggle Scores with Simulated Annealing</title>
		<link>http://www.danvk.org/wp/2009-02-19/sky-high-boggle-scores-with-simulated-annealing/</link>
		<comments>http://www.danvk.org/wp/2009-02-19/sky-high-boggle-scores-with-simulated-annealing/#comments</comments>
		<pubDate>Thu, 19 Feb 2009 08:09:45 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=412</guid>
		<description><![CDATA[Don&#8217;t let the sixteen month hiatus fool you. There&#8217;s just no end to Boggle posts on danvk.org! In case you&#8217;d forgot, we&#8217;ve developed a blazing fast boggle solver capable of scoring 10,000 Boggle boards a second. What to do with this? Other than some interesting analyses, the most interesting question is: What is the highest-scoring [...]]]></description>
			<content:encoded><![CDATA[<p>Don&#8217;t let the <a href="http://www.danvk.org/wp/2007-10-09/a-java-surprise/">sixteen month hiatus</a> fool you. There&#8217;s just no end to Boggle posts on danvk.org!</p>
<p>In case you&#8217;d forgot, we&#8217;ve developed a <a href="http://www.danvk.org/wp/2007-02-10/one-last-boggle-boost/">blazing fast boggle solver</a> capable of scoring 10,000 Boggle boards a second. What to do with this? Other than some <a href="http://www.danvk.org/wp/2007-02-11/some-boggle-statistics/">interesting analyses</a>, the most interesting question is:</p>
<p><b>What is the highest-scoring Boggle Board?</b></p>
<p>In this post, we&#8217;ll try to answer that question using <a href="http://en.wikipedia.org/wiki/Simulated_Annealing">Simulated Annealing</a>. Here&#8217;s a sneak peak at one of the exceptionally word-rich boards we&#8217;ll find:</p>
<style type="text/css">
.board { text-align: center; border-collapse: collapse; }
.board tbody td { border: 1px solid black; border-collapse: collapse; padding: 4px 8px 4px 8px; }
.board tbody td { font-weight: bold; }
.notable { color: red; }
.change td { padding: 2px 5px 2px 5px; }
.mb { font-family: monospace; padding: 0px 4px 0px 4px; }
</style>
<p><center></p>
<table class="board">
<tr>
<td>p</td>
<td>e</td>
<td>r</td>
<td>s</td>
</tr>
<tr>
<td>l</td>
<td>a</td>
<td>t</td>
<td>g</td>
</tr>
<tr>
<td>s</td>
<td>i</td>
<td>n</td>
<td>e</td>
</tr>
<tr>
<td>t</td>
<td>e</td>
<td>r</td>
<td>s</td>
</tr>
<tfoot>
<tr>
<td colspan=4><a href="/boggle.php?quick=perslatgsineters">3625 points</a></td>
</tr>
</tfoot>
</table>
<p></center></p>
<p>Follow me past the fold for more&#8230;</p>
<p><span id="more-412"></span></p>
<p>Here&#8217;s the basic idea of Simulated Annealing:</p>
<ol>
<li>Generate a random board.</li>
<li>Score it.</li>
<li>Change the board somehow.</li>
<li>Score it.</li>
<li>Based on the scores, decide whether to keep the old board or the new one.</li>
<li>Repeat from step 3.</li>
</ol>
<p>If we make good decisions in step #5, the boards we keep will be progressively higher scoring.</p>
<p>The big decisions come in steps #3 and #5. What does it mean to change a board?</p>
<p>I decided to use two basic permutations to change the board: re-rolling a die:</p>
<p><center></p>
<table class="change">
<tr>
<td>
<table class="board">
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
</tr>
<tr>
<td>e</td>
<td>f</td>
<td>g</td>
<td>h</td>
</tr>
<tr>
<td>i</td>
<td>j</td>
<td>k</td>
<td>l</td>
</tr>
<tr>
<td>m</td>
<td>n</td>
<td>o</td>
<td>p</td>
</tr>
<tfoot>
<tr>
<td colspan=4><a href="/boggle.php?quick=abcdefghijklmnop">18 points</a></td>
</tr>
</tfoot>
</table>
</td>
<td> &rarr; </td>
<td>
<table class="board">
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
</tr>
<tr>
<td>e</td>
<td>f</td>
<td>g</td>
<td>h</td>
</tr>
<tr>
<td>i</td>
<td class="notable">r</td>
<td>k</td>
<td>l</td>
</tr>
<tr>
<td>m</td>
<td>n</td>
<td>o</td>
<td>p</td>
</tr>
<tfoot>
<tr>
<td colspan=4><a href="/boggle.php?quick=abcdefghirklmnop">76 points</a></td>
</tr>
</tfoot>
</table>
</td>
</tr>
</table>
<p></center></p>
<p>and swapping two dice:</p>
<p><center></p>
<table class="change">
<tr>
<td>
<table class="board">
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
</tr>
<tr>
<td>e</td>
<td>f</td>
<td>g</td>
<td>h</td>
</tr>
<tr>
<td>i</td>
<td>r</td>
<td>k</td>
<td>l</td>
</tr>
<tr>
<td>m</td>
<td>n</td>
<td>o</td>
<td>p</td>
</tr>
<tfoot>
<tr>
<td colspan=4><a href="/boggle.php?quick=abcdefghirklmnop">76 points</a></td>
</tr>
</tfoot>
</table>
</td>
<td> &rarr; </td>
<td>
<table class="board">
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
<td class="notable">r</td>
</tr>
<tr>
<td>e</td>
<td>f</td>
<td>g</td>
<td>h</td>
</tr>
<tr>
<td>i</td>
<td class="notable">d</td>
<td>k</td>
<td>l</td>
</tr>
<tr>
<td>m</td>
<td>n</td>
<td>o</td>
<td>p</td>
</tr>
<tfoot>
<tr>
<td colspan=4><a href="/boggle.php?quick=abcdefghirklmnop">55 points</a></td>
</tr>
</tfoot>
</table>
</td>
</tr>
</table>
<p></center></p>
<p>Clearly one of these changes was beneficial and the other was not.</p>
<p>Generally speaking, we should accept the changes that increase the score in step #5 and reject the changes that don&#8217;t. This is a perfectly reasonable strategy. It&#8217;s called <a href="http://en.wikipedia.org/wiki/Gradient_Descent">Gradient Descent</a> and is widely-used.</p>
<p>With Simulated Annealing, we sometimes go with the lower-scoring board. The idea is to not get stuck in a rut. Maybe our board is pretty good. It&#8217;s scores higher than all the boards around it. But there are lots of boards a little more distant that are even higher-scoring. With Simulated Annealing, we can take a short-term loss for a long-term gain.</p>
<p>The exact details aren&#8217;t too interesting. If they interest you, take a look at my <a href="http://code.google.com/p/performance-boggle/source/browse/trunk/anneal.cc">code</a>.</p>
<p>Now for the fun part! Here are the results of a sample run. I&#8217;ve concatenated the letters on each row of the board so that they&#8217;ll fit on a single line.</p>
<table>
<tr>
<th>Gen.</th>
<th>Score</th>
<th>Reign</th>
<th>Board</th>
<tr>
<td align=right>0</td>
<td align=right><a href="/boggle.php?quick=kqiqwhyyjthdsibk">19</a></td>
<td align=right>1</td>
<td class=mb>kqiqwhyyjthdsibk</td>
</tr>
<tr>
<td align=right>1</td>
<td align=right><a href="/boggle.php?quick=iqiqjhyywthdskbk">4</a></td>
<td align=right>1</td>
<td class=mb><span class="notable">i</span>qiq<span class="notable">j</span>hyy<span class="notable">w</span>thds<span class="notable">k</span>bk</td>
</tr>
<tr>
<td align=right>2</td>
<td align=right><a href="/boggle.php?quick=ibiqjhyywthdskqk">5</a></td>
<td align=right>1</td>
<td class=mb>i<span class="notable">b</span>iqjhyywthdsk<span class="notable">q</span>k</td>
</tr>
<tr>
<td align=right>3</td>
<td align=right><a href="/boggle.php?quick=ibiqjhcywthdskqk">9</a></td>
<td align=right>1</td>
<td class=mb>ibiqjh<span class="notable">c</span>ywthdskqk</td>
</tr>
<tr>
<td align=right>4</td>
<td align=right><a href="/boggle.php?quick=ibiqjychsthdwkqk">10</a></td>
<td align=right>1</td>
<td class=mb>ibiqj<span class="notable">y</span>c<span class="notable">hs</span>thd<span class="notable">w</span>kqk</td>
</tr>
<tr>
<td align=right>5</td>
<td align=right><a href="/boggle.php?quick=ibicjyqhsthdwkqk">8</a></td>
<td align=right>1</td>
<td class=mb>ibi<span class="notable">c</span>jy<span class="notable">q</span>hsthdwkqk</td>
</tr>
<tr>
<td align=right>6</td>
<td align=right><a href="/boggle.php?quick=ibicjyqdsthywkqk">9</a></td>
<td align=right>1</td>
<td class=mb>ibicjyq<span class="notable">d</span>sth<span class="notable">y</span>wkqk</td>
</tr>
<tr>
<td align=right>7</td>
<td align=right><a href="/boggle.php?quick=ibicjygdhtsywkqk">23</a></td>
<td align=right>1</td>
<td class=mb>ibicjy<span class="notable">g</span>d<span class="notable">h</span>t<span class="notable">s</span>ywkqk</td>
</tr>
<tr>
<td align=right>8</td>
<td align=right><a href="/boggle.php?quick=ibncjygdhtsywkqa">16</a></td>
<td align=right>1</td>
<td class=mb>ib<span class="notable">n</span>cjygdhtsywkq<span class="notable">a</span></td>
</tr>
<tr>
<td align=right>9</td>
<td align=right><a href="/boggle.php?quick=ibncyygdhtsymkqa">15</a></td>
<td align=right>1</td>
<td class=mb>ibnc<span class="notable">y</span>ygdhtsy<span class="notable">m</span>kqa</td>
</tr>
<tr>
<td align=right>10</td>
<td align=right><a href="/boggle.php?quick=ibncyygwhtsytkda">15</a></td>
<td align=right>1</td>
<td class=mb>ibncyyg<span class="notable">w</span>htsy<span class="notable">t</span>k<span class="notable">d</span>a</td>
</tr>
<tr>
<td align=right>11</td>
<td align=right><a href="/boggle.php?quick=ibncyygahtsyhkdw">38</a></td>
<td align=right>1</td>
<td class=mb>ibncyyg<span class="notable">a</span>htsy<span class="notable">h</span>kd<span class="notable">w</span></td>
</tr>
<tr>
<td align=right>12</td>
<td align=right><a href="/boggle.php?quick=ibscyogahtnyhkdw">146</a></td>
<td align=right>2</td>
<td class=mb>ib<span class="notable">s</span>cy<span class="notable">o</span>gaht<span class="notable">n</span>yhkdw</td>
</tr>
<tr>
<td align=right>14</td>
<td align=right><a href="/boggle.php?quick=ibscyogahtnbhkdw">140</a></td>
<td align=right>4</td>
<td class=mb>ibscyogahtn<span class="notable">b</span>hkdw</td>
</tr>
<tr>
<td align=right>18</td>
<td align=right><a href="/boggle.php?quick=ibbcyogahtnshkdw">165</a></td>
<td align=right>2</td>
<td class=mb>ib<span class="notable">b</span>cyogahtn<span class="notable">s</span>hkdw</td>
</tr>
<tr>
<td align=right>20</td>
<td align=right><a href="/boggle.php?quick=ibbcdogahynshktw">159</a></td>
<td align=right>1</td>
<td class=mb>ibbc<span class="notable">d</span>ogah<span class="notable">y</span>nshk<span class="notable">t</span>w</td>
</tr>
<tr>
<td align=right>21</td>
<td align=right><a href="/boggle.php?quick=ibbcdogahynshmtw">169</a></td>
<td align=right>1</td>
<td class=mb>ibbcdogahynsh<span class="notable">m</span>tw</td>
</tr>
<tr>
<td align=right>22</td>
<td align=right><a href="/boggle.php?quick=ibbcdogahynshbtw">151</a></td>
<td align=right>4</td>
<td class=mb>ibbcdogahynsh<span class="notable">b</span>tw</td>
</tr>
<tr>
<td align=right>26</td>
<td align=right><a href="/boggle.php?quick=hbbcdogaiynshbtw">150</a></td>
<td align=right>3</td>
<td class=mb><span class="notable">h</span>bbcdoga<span class="notable">i</span>ynshbtw</td>
</tr>
<tr>
<td align=right>29</td>
<td align=right><a href="/boggle.php?quick=hbbcdogagynshbtw">142</a></td>
<td align=right>2</td>
<td class=mb>hbbcdoga<span class="notable">g</span>ynshbtw</td>
</tr>
<tr>
<td align=right>31</td>
<td align=right><a href="/boggle.php?quick=hbbcdogaygnshbtw">148</a></td>
<td align=right>1</td>
<td class=mb>hbbcdoga<span class="notable">yg</span>nshbtw</td>
</tr>
<tr>
<td align=right>32</td>
<td align=right><a href="/boggle.php?quick=hbbqdogaygnshbtw">151</a></td>
<td align=right>1</td>
<td class=mb>hbb<span class="notable">q</span>dogaygnshbtw</td>
</tr>
<tr>
<td align=right>33</td>
<td align=right><a href="/boggle.php?quick=hbtmdogaygnshbtw">174</a></td>
<td align=right>7</td>
<td class=mb>hb<span class="notable">tm</span>dogaygnshbtw</td>
</tr>
<tr>
<td align=right>40</td>
<td align=right><a href="/boggle.php?quick=hdtmbogaygnshbtw">175</a></td>
<td align=right>2</td>
<td class=mb>h<span class="notable">d</span>tm<span class="notable">b</span>ogaygnshbtw</td>
</tr>
<tr>
<td align=right>42</td>
<td align=right><a href="/boggle.php?quick=hdtmbogaygnstbtw">172</a></td>
<td align=right>3</td>
<td class=mb>hdtmbogaygns<span class="notable">t</span>btw</td>
</tr>
<tr>
<td align=right>45</td>
<td align=right><a href="/boggle.php?quick=hdtmbogaygnetbtw">165</a></td>
<td align=right>1</td>
<td class=mb>hdtmbogaygn<span class="notable">e</span>tbtw</td>
</tr>
<tr>
<td align=right>46</td>
<td align=right><a href="/boggle.php?quick=hdtmbogaygnetbts">274</a></td>
<td align=right>1</td>
<td class=mb>hdtmbogaygnetbt<span class="notable">s</span></td>
</tr>
<tr>
<td align=right>47</td>
<td align=right><a href="/boggle.php?quick=hdtmbogabgnetyts">298</a></td>
<td align=right>5</td>
<td class=mb>hdtmboga<span class="notable">b</span>gnet<span class="notable">y</span>ts</td>
</tr>
<tr>
<td align=right>52</td>
<td align=right><a href="/boggle.php?quick=hdtmbogabgnswyte">296</a></td>
<td align=right>8</td>
<td class=mb>hdtmbogabgn<span class="notable">sw</span>yt<span class="notable">e</span></td>
</tr>
<tr>
<td align=right>60</td>
<td align=right><a href="/boggle.php?quick=hdtmboeabgnswytg">387</a></td>
<td align=right>1</td>
<td class=mb>hdtmbo<span class="notable">e</span>abgnswyt<span class="notable">g</span></td>
</tr>
<tr>
<td align=right>61</td>
<td align=right><a href="/boggle.php?quick=hdtgboeabmnswytg">403</a></td>
<td align=right>7</td>
<td class=mb>hdt<span class="notable">g</span>boeab<span class="notable">m</span>nswytg</td>
</tr>
<tr>
<td align=right>68</td>
<td align=right><a href="/boggle.php?quick=hdtpboeabmnswytg">409</a></td>
<td align=right>3</td>
<td class=mb>hdt<span class="notable">p</span>boeabmnswytg</td>
</tr>
<tr>
<td align=right>71</td>
<td align=right><a href="/boggle.php?quick=hdtpboeabmnsgytg">413</a></td>
<td align=right>6</td>
<td class=mb>hdtpboeabmns<span class="notable">g</span>ytg</td>
</tr>
<tr>
<td align=right>77</td>
<td align=right><a href="/boggle.php?quick=hptdboeabmnsgytg">419</a></td>
<td align=right>3</td>
<td class=mb>h<span class="notable">p</span>t<span class="notable">d</span>boeabmnsgytg</td>
</tr>
<tr>
<td align=right>80</td>
<td align=right><a href="/boggle.php?quick=hptdbaeobmnsgytg">416</a></td>
<td align=right>8</td>
<td class=mb>hptdb<span class="notable">a</span>e<span class="notable">o</span>bmnsgytg</td>
</tr>
<tr>
<td align=right>88</td>
<td align=right><a href="/boggle.php?quick=phtdbaeobmnsgytg">421</a></td>
<td align=right>9</td>
<td class=mb><span class="notable">ph</span>tdbaeobmnsgytg</td>
</tr>
<tr>
<td align=right>97</td>
<td align=right><a href="/boggle.php?quick=phtdbaeoymnsgytg">449</a></td>
<td align=right>40</td>
<td class=mb>phtdbaeo<span class="notable">y</span>mnsgytg</td>
</tr>
<tr>
<td align=right>137</td>
<td align=right><a href="/boggle.php?quick=phtsbaeoymnsgytg">454</a></td>
<td align=right>2</td>
<td class=mb>pht<span class="notable">s</span>baeoymnsgytg</td>
</tr>
<tr>
<td align=right>139</td>
<td align=right><a href="/boggle.php?quick=phtseaeoymnsgytg">463</a></td>
<td align=right>11</td>
<td class=mb>phts<span class="notable">e</span>aeoymnsgytg</td>
</tr>
<tr>
<td align=right>150</td>
<td align=right><a href="/boggle.php?quick=phtsmaeoyensgstg">581</a></td>
<td align=right>3</td>
<td class=mb>phts<span class="notable">m</span>aeoy<span class="notable">e</span>nsg<span class="notable">s</span>tg</td>
</tr>
<tr>
<td align=right>153</td>
<td align=right><a href="/boggle.php?quick=yhtsmaeopensgstg">662</a></td>
<td align=right>26</td>
<td class=mb><span class="notable">y</span>htsmaeo<span class="notable">p</span>ensgstg</td>
</tr>
<tr>
<td align=right>179</td>
<td align=right><a href="/boggle.php?quick=yhtsmaespenogstg">690</a></td>
<td align=right>1</td>
<td class=mb>yhtsmae<span class="notable">s</span>pen<span class="notable">o</span>gstg</td>
</tr>
<tr>
<td align=right>180</td>
<td align=right><a href="/boggle.php?quick=lhtsmaespenogstg">734</a></td>
<td align=right>2</td>
<td class=mb><span class="notable">l</span>htsmaespenogstg</td>
</tr>
<tr>
<td align=right>182</td>
<td align=right><a href="/boggle.php?quick=lctsoaespenogstg">754</a></td>
<td align=right>13</td>
<td class=mb>l<span class="notable">c</span>ts<span class="notable">o</span>aespenogstg</td>
</tr>
<tr>
<td align=right>195</td>
<td align=right><a href="/boggle.php?quick=lctsoasepenogstg">849</a></td>
<td align=right>1</td>
<td class=mb>lctsoa<span class="notable">se</span>penogstg</td>
</tr>
<tr>
<td align=right>196</td>
<td align=right><a href="/boggle.php?quick=lctseasepenogstg">912</a></td>
<td align=right>39</td>
<td class=mb>lcts<span class="notable">e</span>asepenogstg</td>
</tr>
<tr>
<td align=right>235</td>
<td align=right><a href="/boggle.php?quick=lctseasepenoistg">974</a></td>
<td align=right>10</td>
<td class=mb>lctseasepeno<span class="notable">i</span>stg</td>
</tr>
<tr>
<td align=right>245</td>
<td align=right><a href="/boggle.php?quick=lctseasedenoistg">978</a></td>
<td align=right>10</td>
<td class=mb>lctsease<span class="notable">d</span>enoistg</td>
</tr>
<tr>
<td align=right>255</td>
<td align=right><a href="/boggle.php?quick=lctseasedsnoietg">1046</a></td>
<td align=right>25</td>
<td class=mb>lctseased<span class="notable">s</span>noi<span class="notable">e</span>tg</td>
</tr>
<tr>
<td align=right>280</td>
<td align=right><a href="/boggle.php?quick=lctseasedsrointg">1281</a></td>
<td align=right>53</td>
<td class=mb>lctseaseds<span class="notable">r</span>oi<span class="notable">n</span>tg</td>
</tr>
<tr>
<td align=right>333</td>
<td align=right><a href="/boggle.php?quick=lctseasedsronitg">1511</a></td>
<td align=right>2</td>
<td class=mb>lctseasedsro<span class="notable">ni</span>tg</td>
</tr>
<tr>
<td align=right>335</td>
<td align=right><a href="/boggle.php?quick=lctseasedsronitg">1511</a></td>
<td align=right>8</td>
<td class=mb>lctseasedsronitg</td>
</tr>
<tr>
<td align=right>343</td>
<td align=right><a href="/boggle.php?quick=lctseaiedsronitg">1515</a></td>
<td align=right>17</td>
<td class=mb>lctsea<span class="notable">i</span>edsronitg</td>
</tr>
<tr>
<td align=right>360</td>
<td align=right><a href="/boggle.php?quick=lctseaiedsronitp">1537</a></td>
<td align=right>2</td>
<td class=mb>lctseaiedsronit<span class="notable">p</span></td>
</tr>
<tr>
<td align=right>362</td>
<td align=right><a href="/boggle.php?quick=lctseaiedtronisp">1643</a></td>
<td align=right>32</td>
<td class=mb>lctseaied<span class="notable">t</span>roni<span class="notable">s</span>p</td>
</tr>
<tr>
<td align=right>394</td>
<td align=right><a href="/boggle.php?quick=lstseaiedtronisp">1708</a></td>
<td align=right>21</td>
<td class=mb>l<span class="notable">s</span>tseaiedtronisp</td>
</tr>
<tr>
<td align=right>415</td>
<td align=right><a href="/boggle.php?quick=lstseiaedtronisp">1727</a></td>
<td align=right>46</td>
<td class=mb>lstse<span class="notable">ia</span>edtronisp</td>
</tr>
<tr>
<td align=right>461</td>
<td align=right><a href="/boggle.php?quick=lstseiaedtrinosp">1744</a></td>
<td align=right>40</td>
<td class=mb>lstseiaedtr<span class="notable">i</span>n<span class="notable">o</span>sp</td>
</tr>
<tr>
<td align=right>501</td>
<td align=right><a href="/boggle.php?quick=lstseiaentrinosp">1873</a></td>
<td align=right>36</td>
<td class=mb>lstseiae<span class="notable">n</span>trinosp</td>
</tr>
<tr>
<td align=right>537</td>
<td align=right><a href="/boggle.php?quick=lstseiaentrisosp">2053</a></td>
<td align=right>9</td>
<td class=mb>lstseiaentri<span class="notable">s</span>osp</td>
</tr>
<tr>
<td align=right>546</td>
<td align=right><a href="/boggle.php?quick=lstseiaentrigosp">2162</a></td>
<td align=right>13</td>
<td class=mb>lstseiaentri<span class="notable">g</span>osp</td>
</tr>
<tr>
<td align=right>559</td>
<td align=right><a href="/boggle.php?quick=sltseiaentrigosp">2445</a></td>
<td align=right>42</td>
<td class=mb><span class="notable">sl</span>tseiaentrigosp</td>
</tr>
<tr>
<td align=right>601</td>
<td align=right><a href="/boggle.php?quick=sltseiaentrigosp">2445</a></td>
<td align=right>21</td>
<td class=mb>sltseiaentrigosp</td>
</tr>
<tr>
<td align=right>622</td>
<td align=right><a href="/boggle.php?quick=sltseiaentrigesp">2524</a></td>
<td align=right>58</td>
<td class=mb>sltseiaentrig<span class="notable">e</span>sp</td>
</tr>
<tr>
<td align=right>680</td>
<td align=right><a href="/boggle.php?quick=stlseiaentrigesp">2597</a></td>
<td align=right>37</td>
<td class=mb>s<span class="notable">tl</span>seiaentrigesp</td>
</tr>
<tr>
<td align=right>717</td>
<td align=right><a href="/boggle.php?quick=stlseiaentragesp">2614</a></td>
<td align=right>232</td>
<td class=mb>stlseiaentr<span class="notable">a</span>gesp</td>
</tr>
<tr>
<td align=right>949</td>
<td align=right><a href="/boggle.php?quick=stlseiaentrpgesa">3090</a></td>
<td align=right>276</td>
<td class=mb>stlseiaentr<span class="notable">p</span>ges<span class="notable">a</span></td>
</tr>
<tr>
<td align=right>1225</td>
<td align=right><a href="/boggle.php?quick=stlseiaentrpdesa">3151</a></td>
<td align=right>26</td>
<td class=mb>stlseiaentrp<span class="notable">d</span>esa</td>
</tr>
<tr>
<td align=right>1251</td>
<td align=right><a href="/boggle.php?quick=stlseiaentrpdeso">3182</a></td>
<td align=right>n/a</td>
<td class=mb>stlseiaentrpdes<span class="notable">o</span></td>
</tr>
</table>
<p>Some fun words on that last board: &#8220;desperate&#8221;, &#8220;entreaties&#8221;, &#8220;operated&#8221; and &#8220;serenest&#8221;. No shortage of 11-pointers on this board!</p>
<p>That&#8217;s all for now. Next time we&#8217;ll look at some of the highest-scoring boards that simulated annealing finds.</p>
<p>As usual, you can find all the source code for this project on the <a href="http://code.google.com/p/performance-boggle/">performance-boggle</a> project at Google Code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2009-02-19/sky-high-boggle-scores-with-simulated-annealing/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>A Java Surprise</title>
		<link>http://www.danvk.org/wp/2007-10-09/a-java-surprise/</link>
		<comments>http://www.danvk.org/wp/2007-10-09/a-java-surprise/#comments</comments>
		<pubDate>Wed, 10 Oct 2007 06:44:25 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=224</guid>
		<description><![CDATA[I&#8217;ve always been a Java and Eclipse naysayer, but I&#8217;m afraid new experiences are forcing me to reevaluate my skepticism. The last time I used Java was JDK 1.3 on a Sparc workstation back in early 2004. Eclipse was hella slow on that hardware, and somehow my workspace wound up in a temporary directory. This [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://www.danvk.org/wp/wp-content/uploads/2007/10/java.png' alt='java.png' align=right style="padding-left: 10px;" /><br />
I&#8217;ve always been a <a href="http://en.wikipedia.org/wiki/Java_(programming_language)">Java</a> and <a href="http://en.wikipedia.org/wiki/Eclipse_(software)">Eclipse</a> naysayer, but I&#8217;m afraid new experiences are forcing me to reevaluate my skepticism. The last time I used Java was JDK 1.3 on a Sparc workstation back in early 2004. Eclipse was hella slow on that hardware, and somehow my workspace wound up in a temporary directory. This was a very bad thing, because as soon as I logged out, my project was gone forever. So I had good reason to swear off Eclipse.</p>
<p>More generally, Java left off a mighty stink back in 2004. Any GUI that I ran on the Mac would look out of place and felt clunky. Performance was poor. But in retrospect, I suspect much of the rank Java smell was really coming from the <a href="https://sys.cs.rice.edu/course/comp314/07/">design patterns gibberish</a> I was being force-fed at the same time. Why use a simple array when you could use an AbstractListFactory that does the same thing with 10x code bloat?</p>
<p>Regular readers only get one guess what program I wrote to get in the swing of things.<br />
<span id="more-224"></span><br />
The <a href="http://performance-boggle.googlecode.com/svn/trunk/">C++ code</a> translated almost line-for-line to Java. Most of the changes were either syntax (&#8220;->&#8221; to &#8220;.&#8221;) or swapping <code>String</code> for <code>char*</code>. It took a while to remember that everything is a pointer in Java. The Java statement <code>Trie t = new Trie();</code> is the equivalent of C++&#8217;s <code>Trie* t = new Trie;</code> and not plain old <code>Trie t;</code>, which uses the stack. Another major pain was the lack of unsigned types, which I used as hash codes in some tests.</p>
<p>Here&#8217;s the <a href="http://performance-boggle.googlecode.com/svn/trunk/java/boggle/">Java code</a>, for those interested. I expected Java code to be an order of magnitude slower than the <a href="http://performance-boggle.googlecode.com/svn/trunk/">equivalent C++</a>, so this initial benchmark surprised me:</p>
<pre>
C++:  Evaluated 21632 boards in 0.694 seconds = 31,162 bds/sec
Java: Evaluated 21632 boards in 1.108 seconds = 19,523 bds/sec
</pre>
<p>That&#8217;s only a <b>37% performance penalty</b>, far less than the 90% or more I was expecting. Since my code doesn&#8217;t create/destroy any objects during the critical section, I&#8217;m really testing the effectiveness of the JIT. Since this code is a direct C conversion, it makes sense that it does well.</p>
<p>I don&#8217;t understand the internals of Java well enough to know how valid my benchmark is. Profiling C++ code is relatively straightforward, since nothing is going on behind your back. Not the case with Java. For example, does that 1.108 seconds include the time it took the JIT to compile my code? That might explain the whole perf difference. Also, am I fully optimizing? I hear there&#8217;s a difference between the <a href="http://java.sun.com/j2se/1.3/docs/guide/performance/hotspot.html#client">client</a> and <a href="http://java.sun.com/j2se/1.3/docs/guide/performance/hotspot.html#server">server</a> JITs. Which one am I using? How can I tell? Lazyweb?</p>
<p>A few more thoughts on the whole experience:</p>
<ul>
<li>Eclipse is just great, especially for someone whose knowledge of the JDK is rusty. Having &#8220;<code>string.</code>&#8221; bring up a list of methods was great. This was less useful for more obscure Java-isms, like <code>System.getProperty("user.dir")</code> to get the current working directory.</li>
<li>When Eclipse spots an error in your code, it suggests a solution, which you can double-click to perform. This was just perfect for a rusty coder. It added lines like <code>import java.io.File;</code> to my code, which would have taken me a while to figure out on my own. That&#8217;s always a nuisance in C++.</li>
<li>I can&#8217;t figure out what command line Eclipse is using to run my code. I have no idea how it&#8217;s running my unit tests. Is there any way of finding this out?</li>
<li>jUnit was very easy to use inside Eclipse. I particularly liked the ability to write unit tests inside the class they were testing. Just tag a method with <code>@Test</code> and it becomes a unit test. Very cool.</li>
<li>I found the whole StringBuilder business pretty clunky. Writing <code>"a" + "b"</code> is special kludge for <code>new StringBuilder().Append("a").Append("b").toString()</code>. I also missed <code>printf</code> when writing to stdout. Is there no natural way to mix numbers and strings?</li>
<li>Java GUIs on the Mac still aren&#8217;t quite there. When I moused over the icons in Eclipse, there was noticeable flicker.</li>
</ul>
<p>A tool like Eclipse is a great boon in understanding a large, foreign code base. One thing I&#8217;ve discovered in my past year at Google is that, while I&#8217;ve become a fairly good coder through experience, I have almost no external experience working with other people&#8217;s code. Make no mistake, navigating other people&#8217;s code is a skill. And to a surprising extent, it&#8217;s a skill disjoint from coding itself. We have a few tools to help with this at Google, but nothing quite so low-latency as what Eclipse pops up when you press type a period. The possibility of tools like Eclipse is a strong argument for languages with a simple syntax. When anyone can parse a language, they can build amazing tools like this one.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2007-10-09/a-java-surprise/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How many Boggle boards are there?</title>
		<link>http://www.danvk.org/wp/2007-08-02/how-many-boggle-boards-are-there/</link>
		<comments>http://www.danvk.org/wp/2007-08-02/how-many-boggle-boards-are-there/#comments</comments>
		<pubDate>Fri, 03 Aug 2007 03:45:32 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>
		<category><![CDATA[math]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=195</guid>
		<description><![CDATA[I&#8217;ve taken a several months break from my Boggle series, mostly because I think everyone got tired of it. I&#8217;m going to come back to it, but hopefully at a slower pace this time around. Last time, we completed a board solver that could score 10,000 boards per second. So what to do with all [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve taken a several months break from my <a href="http://www.danvk.org/wp/?cat=10">Boggle series</a>, mostly because I think everyone got tired of it. I&#8217;m going to come back to it, but hopefully at a slower pace this time around.</p>
<p><a href="http://www.danvk.org/wp/?p=89">Last time</a>, we completed a board solver that could score 10,000 boards per second. So what to do with all that power? One option was to <a href="http://www.danvk.org/wp/?p=91">compute statistics</a> on random boards. Another is to hunt for the holy grail of Boggle: the highest possible scoring Boggle board. The next few posts will be devoted to the search for this board.</p>
<p>Before undertaking any search, you need to get a feel for your search space. In our case, that&#8217;s the set of all 4&#215;4 Boggle boards. How many are there? We can do a few back-of-the-envelope calculations.</p>
<p>To create a board, you roll 16 dice. Each has six possible letters on it, which gives 6^16 possibilities. These dice land in some permutation on the board, which gives another factor of 16!. Finally, a 4&#215;4 board has eight-fold symmetry, which takes us down to 6^16 * 16! / 8 = 7.3e24 &asymp; 2 ^ 83.</p>
<p>That&#8217;s one upper bound. But it assumed that all 6*16 = 96 symbols on the dice were unique. Obviously they&#8217;re not. After a roll, each of the 16 squares will have one of 26 letters on it. Divide by the symmetries, and you get 26 ^ 16 / 8 = 5e21 &asymp; 2^72. Much better!</p>
<p>I haven&#8217;t been able to come up with any better upper bounds than these. The main flaw in the second approximation is that not all boards can be rolled with the sixteen dice that <a href="http://hasbro.com/default.cfm?page=ps_results&#038;product_id=9619">Hasbro</a> provides. A board of all z&#8217;s or qu&#8217;s simply can&#8217;t occur. If we knew the probability that any sixteen character sequence could be rolled, this would give a true approximation of the number of distinct boards.</p>
<p>The easiest way to do this is with a computer program. It picks a random sequence of sixteen characters, checks whether this board can be rolled, and repeats several thousand times. I believe that checking whether a given board can be rolled is NP-Complete, but in this case the greedy approximation works quite well. I wrote a program (leave a comment if you want to see it) to do this, and processed one million 16-character sequences. Only 84,492 could be represented with the usual dice, or 8.4%. This gives a total of</p>
<p>(26 ^ 16 / 8) * (84,492 / 1,000,000) = 4.6e20 &asymp; 2^69.</p>
<p>If you like confidence intervals, my sample size of one million boards gives a 95% confidence interval of [4.545e24, 4.666e24] for the total number of boards. Pretty good.</p>
<p>So, assuming we could enumerate all these boards quickly, how long would it take for our faster solver to find the best board? At 10k boards/sec, we&#8217;re looking at 4.5e16 seconds = 1.9 billion years! Clearly we need to do better.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2007-08-02/how-many-boggle-boards-are-there/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>JRuby Performance, Yowch!</title>
		<link>http://www.danvk.org/wp/2007-05-02/jruby-performance-yowch/</link>
		<comments>http://www.danvk.org/wp/2007-05-02/jruby-performance-yowch/#comments</comments>
		<pubDate>Thu, 03 May 2007 05:58:13 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=141</guid>
		<description><![CDATA[I took JRuby 0.9.9 for a spin with the exceptionally-inefficient Boggle program from a few months back. Here are the numbers: $ time ruby short.rb c a t d l i n e m a r o p e t s 2338 ruby short.rb c a t d l i n e m a r [...]]]></description>
			<content:encoded><![CDATA[<p>I took <a href="http://jruby.codehaus.org/">JRuby</a> 0.9.9 for a spin with the <a href="http://www.danvk.org/wp/?p=65">exceptionally-inefficient Boggle program</a> from a few months back. Here are the numbers:</p>
<pre>$ <b>time ruby short.rb c a t d l i n e m a r o p e t s</b>
2338
ruby short.rb c a t d l i n e m a r o p e t s  241.95s user 1.20s system 97% cpu 4:08.35 total</pre>
<pre>$ <b>time jruby short.rb c a t d l i n e m a r o p e t s</b>
2338
jruby short.rb c a t d l i n e m a r o p e t s  1178.86s user 40.84s system 108% cpu 18:44.44 total</pre>
<p>I&#8217;d heard JRuby was slow, but this is spectacular. Four times slower than the already-slow Ruby?</p>
<p>I&#8217;d always thought that the point of JRuby was to run Ruby programs on the JVM, and hence get the benefits of the JVM&#8217;s JIT. I guess not. With that kind of performance, the only possible justification is the ability to use Java libraries.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2007-05-02/jruby-performance-yowch/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Initial Impressions of D</title>
		<link>http://www.danvk.org/wp/2007-02-16/initial-impressions-of-d/</link>
		<comments>http://www.danvk.org/wp/2007-02-16/initial-impressions-of-d/#comments</comments>
		<pubDate>Fri, 16 Feb 2007 07:07:45 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=97</guid>
		<description><![CDATA[I got curious about the programming language D after noticing it outperform C++ in the somewhat-silly Computer Language Shootout and reading Steve Yegge&#8217;s thoughts on it. I&#8217;ve played around it for the past few days. Here&#8217;s some thoughts. First of all, D is what you might call a &#8220;low PageRank language.&#8221; If you search for [...]]]></description>
			<content:encoded><![CDATA[<p>I got curious about the programming language <a href="http://www.digitalmars.com/d/">D</a> after noticing it <a href="http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&#038;lang=all">outperform C++</a> in the somewhat-silly <a href="http://shootout.alioth.debian.org/gp4/index.php">Computer Language Shootout</a> and reading <a href="http://steve-yegge.blogspot.com/2007/02/next-big-language.html">Steve Yegge&#8217;s thoughts</a> on it. I&#8217;ve played around it for the past few days. Here&#8217;s some thoughts.</p>
<p>First of all, D is what you might call a &#8220;low PageRank language.&#8221; If you <a href="http://www.google.com/search?q=D">search for &#8216;D&#8217;</a>, there&#8217;s nothing related to the language until result #15. The next result isn&#8217;t until #160, and it&#8217;s pretty random. Contrast that with <a href="http://www.google.com/search?q=C">C</a>. This makes searching for help on D almost impossible. Try <a href="D slow file I/O">&#8220;D slow file I/O&#8221;</a> for a taste. This isn&#8217;t necessarily Google&#8217;s fault, either. There&#8217;s just not that many good D resources online yet.<br />
<span id="more-97"></span></p>
<p>So why&#8217;d I search for that? Here&#8217;s a program in C++:</p>
<p>// &#8230; headers &#8230;<br />
int main(int argc, char** argv) {<br />
  ifstream f(argv[1]);<br />
  string word;<br />
  vector<string> words;<br />
  while (f >> word) {<br />
    words.push_back(word);<br />
  }<br />
  cout << "Words: " << words.size() << endl;<br />
  return 0;<br />
}</p>
<p>It loads the 173,528-word <a href="http://www.everything2.com/index.pl?node_id=1736033">ENABLE2K</a> word list in 0.277 seconds. Here&#8217;s the same program in D:</p>
<p>import std.stdio;<br />
import std.stream;</p>
<p>int main(char[][] args) {<br />
  auto f = new File(args[1]);<br />
  char[][] words;<br />
  while (!f.eof()) {<br />
    char[] word;<br />
    word = f.readLine(word);<br />
    words ~= word;<br />
  }<br />
  writefln(&#8220;Words: &#8220;, words.length);<br />
  return 0;<br />
}</p>
<p>This takes 7.590 seconds to run. Why is file I/O in D so slow? Turns out that we need to turn on buffered I/O, but  it took stumbling on <a href="http://www.digitalmars.com/d/archives/digitalmars/D/learn/2490.html">this forum post</a> to find that out. Replace &#8220;File&#8221; with &#8220;BufferedFile&#8221; in that code and the runtime drops to 0.338 seconds.</p>
<p>Even the <a href="http://www.digitalmars.com/d/phobos/phobos.html">official documentation</a> is pretty bad. Here&#8217;s a real gem: <a href="http://www.digitalmars.com/d/phobos/std_c_time.html">std.c.time</a>. Even better is what I found when I tried to time a section of code. I was happy to find <a href="http://www.dsource.org/projects/tutorials/wiki/StdPerfExample">this tutorial</a> about HighPerformanceCounter in the std.perf library. Of course, the official documentation doesn&#8217;t even acknowledge the existence of std.perf, but that&#8217;s OK. I couldn&#8217;t get the example to compile, though. After some <a href="http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&#038;group=digitalmars.D.learn&#038;artnum=5325">more scrounging</a>, I discovered that this was a Windows-only class. What I wanted on my Mac was PerformanceCounter, but I had to manually peruse the <code>/usr/include/d/4.0.1/std/perf.d</code> file to find that out. What gives?</p>
<p>I&#8217;ll give you one guess what my standard test program for new languages is. (<a href="http://www.danvk.org/wp/?p=67">hint</a>) This was surprisingly easy once I got the hang of things. I&#8217;m a big fan of the <code>debug</code> keyword. If you write something like</p>
<p><code>debug(2) writefln("Dan was here");</code></p>
<p>Then the line will execute only if you compile with <code>--fdebug=2</code> or higher. This is a nice way to avoid commenting out debug statements. When you compile with <code>--frelease</code>, the statement disappears entirely. No runtime cost.</p>
<p>Some other things I found interesting:</p>
<ul>
<li>A real module system. No more <code>.h</code> header and <code>.cc</code> implementation silliness.</li>
<li>There&#8217;s a <code>unittest</code> keyword. When you write code in a <code>unittest</code> block, it automatically runs before your code when you pass the <code>-funittest</code> flag to the gdc. Very cool!</li>
<li>The <code>writefln</code> function is way smarter than <code>printf</code>. You can do things like <code>writefln("x: ", x)</code> and avoid having to guess whether <code>x</code> needs a &#8220;%d&#8221; or a &#8220;%lu&#8221;. You can also pass just about anything into a &#8220;%s&#8221; argument and expect a reasonable conversion to a string.</li>
<li>The <code>private</code> keyword makes variables module-private, not class-private like in C++. Every class in the same module is effectively your <code>friend</code>. Not sure what I think of this.</li>
<li>Arrays are <i>finally</i> declared like this: <code>char[] string</code>.</li>
<li>The <code>auto</code> keyword does type inference, just like it <a href="http://www.informit.com/guides/content.asp?g=cplusplus&#038;seqNum=219&#038;rl=1">will</a> in C++0x.</code>
<li>The <code>~</code> operator is cool. It appends to arrays. It's going to be hard for me to get used to <code>~=</code> not meaning "apply regex" like it does in Perl.</li>
<li>Array accesses are bounds-checked in debug binaries. This is fantastic, since it means you'll get meaningful errors in more meaningful locations.</li>
<li>There's no <code>-></code> arrow operator. You just use <code>.</code> instead. This has taken a lot of getting used to.</li>
</ul>
<p>Anyways, here's the perf for my boggle program:</p>
<pre>
$ <b>gdc -O3 -fno-bounds-check -finline-functions -frelease -Wall -o test trie.d btest.d boggler.d</b>
$ <b>./test</b>
Loaded 172203 words
Loaded 50000 test boards
Elapsed time: 4666252 us
Perf: 10715.2 bds/sec
Avg. Score: 141.173 pts/bd
</pre>
<p>That's pretty damn good! Slightly better than the <a href="http://www.danvk.org/wp/?p=89">best C++ program</a> I've published on this site, though not better than the best C++ Boggler I've ever written. It's interesting what a huge difference the compiler flags make. If you drop the "-frelease" flag, perf drops to 7500 bds/sec. Without the "-fno-bounds-check" flag, we're down to 6200 bds/sec. That makes reviewing the terse <a href="http://dgcc.sourceforge.net/gdc/manual.html">GDC manual</a> essential.</p>
<p>So, conclusions. D is a very young language with lots of promise. I'd hesitate to call it the "next big thing," though. While it's leaps and bounds higher level than C, I've found that the expressiveness is about on par with code written with the C++ STL. The main differences are the module system and the presence of garbage collection, important features that didn't really come out in re-implementing Boggle. My biggest complaint is the lack of documentation. There's no English books on D, it's practically unsearchable, and the official documentation is pathetic. Digital Mars would do their language a great service by writing some tutorials and a more complete reference.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2007-02-16/initial-impressions-of-d/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Some Boggle Statistics</title>
		<link>http://www.danvk.org/wp/2007-02-11/some-boggle-statistics/</link>
		<comments>http://www.danvk.org/wp/2007-02-11/some-boggle-statistics/#comments</comments>
		<pubDate>Mon, 12 Feb 2007 05:46:52 +0000</pubDate>
		<dc:creator>danvk</dc:creator>
				<category><![CDATA[boggle]]></category>

		<guid isPermaLink="false">http://www.danvk.org/wp/?p=91</guid>
		<description><![CDATA[With a fast boggle solver in hand, it&#8217;s time for some fun statistics. These are all based on boggle boards rolled with real boggle dice. I&#8217;m going sans-code this time, but if you&#8217;re interested in seeing it, feel free to holla. Most common words: 3 letters &#160; 4 letters &#160; 5 letters Word Freq (%) [...]]]></description>
			<content:encoded><![CDATA[<p>With a fast boggle solver in hand, it&#8217;s time for some fun statistics. These are all based on boggle boards rolled with real boggle dice. I&#8217;m going sans-code this time, but if you&#8217;re interested in seeing it, feel free to holla.</p>
<p>Most common words:</p>
<table>
<tr>
<th colspan=2>3 letters</th>
<td>&nbsp;</td>
<th colspan=2>4 letters</th>
<td>&nbsp;</td>
<th colspan=2>5 letters</th>
</tr>
<tr>
<td><b>Word</b></td>
<td><b>Freq (%)</b></td>
<td>&nbsp;</td>
<td><b>Word</b></td>
<td><b>Freq (%)</b></td>
<td>&nbsp;</td>
<td><b>Word</b></td>
<td><b>Freq (%)</b></td>
</tr>
<tr>
<td>toe</td>
<td>19.258</td>
<td>&nbsp;</td>
<td>teen</td>
<td>6.718</td>
<td>&nbsp;</td>
<td>eaten</td>
<td>2.034</td>
</tr>
<tr>
<td>tee</td>
<td>19.074</td>
<td>&nbsp;</td>
<td>tees</td>
<td>6.564</td>
<td>&nbsp;</td>
<td>enate</td>
<td>2</td>
</tr>
<tr>
<td>ten</td>
<td>17.944</td>
<td>&nbsp;</td>
<td>tent</td>
<td>6.02</td>
<td>&nbsp;</td>
<td>sente</td>
<td>1.954</td>
</tr>
<tr>
<td>net</td>
<td>17.944</td>
<td>&nbsp;</td>
<td>note</td>
<td>5.976</td>
<td>&nbsp;</td>
<td>setae</td>
<td>1.944</td>
</tr>
<tr>
<td>tea</td>
<td>17.65</td>
<td>&nbsp;</td>
<td>tone</td>
<td>5.838</td>
<td>&nbsp;</td>
<td>tense</td>
<td>1.86</td>
</tr>
<tr>
<td>set</td>
<td>17.51</td>
<td>&nbsp;</td>
<td>teat</td>
<td>5.804</td>
<td>&nbsp;</td>
<td>tease</td>
<td>1.856</td>
</tr>
<tr>
<td>eta</td>
<td>17.176</td>
<td>&nbsp;</td>
<td>toes</td>
<td>5.664</td>
<td>&nbsp;</td>
<td>teeth</td>
<td>1.788</td>
</tr>
<tr>
<td>ate</td>
<td>17.176</td>
<td>&nbsp;</td>
<td>toea</td>
<td>5.548</td>
<td>&nbsp;</td>
<td>eater</td>
<td>1.788</td>
</tr>
<tr>
<td>tae</td>
<td>16.518</td>
<td>&nbsp;</td>
<td>nets</td>
<td>5.432</td>
<td>&nbsp;</td>
<td>teens</td>
<td>1.712</td>
</tr>
<tr>
<td>eat</td>
<td>16.518</td>
<td>&nbsp;</td>
<td>test</td>
<td>5.344</td>
<td>&nbsp;</td>
<td>seton</td>
<td>1.702</td>
</tr>
<tr>
<td>tie</td>
<td>16.432</td>
<td>&nbsp;</td>
<td>rete</td>
<td>5.208</td>
<td>&nbsp;</td>
<td>notes</td>
<td>1.702</td>
</tr>
<tr>
<td>het</td>
<td>15.684</td>
<td>&nbsp;</td>
<td>nett</td>
<td>5.204</td>
<td>&nbsp;</td>
<td>tents</td>
<td>1.646</td>
</tr>
<tr>
<td>ret</td>
<td>15.108</td>
<td>&nbsp;</td>
<td>nest</td>
<td>5.174</td>
<td>&nbsp;</td>
<td>retie</td>
<td>1.632</td>
</tr>
<tr>
<td>eth</td>
<td>14.938</td>
<td>&nbsp;</td>
<td>tens</td>
<td>5.172</td>
<td>&nbsp;</td>
<td>steno</td>
<td>1.624</td>
</tr>
<tr>
<td>oes</td>
<td>14.698</td>
<td>&nbsp;</td>
<td>sent</td>
<td>5.156</td>
<td>&nbsp;</td>
<td>sheet</td>
<td>1.618</td>
</tr>
<tr>
<td>the</td>
<td>14.542</td>
<td>&nbsp;</td>
<td>neat</td>
<td>5.146</td>
<td>&nbsp;</td>
<td>ester</td>
<td>1.618</td>
</tr>
<tr>
<td>eon</td>
<td>14.474</td>
<td>&nbsp;</td>
<td>etna</td>
<td>5.144</td>
<td>&nbsp;</td>
<td>oaten</td>
<td>1.61</td>
</tr>
<tr>
<td>one</td>
<td>14.366</td>
<td>&nbsp;</td>
<td>ante</td>
<td>5.144</td>
<td>&nbsp;</td>
<td>teats</td>
<td>1.608</td>
</tr>
<tr>
<td>ose</td>
<td>13.82</td>
<td>&nbsp;</td>
<td>thee</td>
<td>5.064</td>
<td>&nbsp;</td>
<td>tones</td>
<td>1.606</td>
</tr>
<tr>
<td>see</td>
<td>13.78</td>
<td>&nbsp;</td>
<td>tote</td>
<td>5.052</td>
<td>&nbsp;</td>
<td>enter</td>
<td>1.596</td>
</tr>
</table>
<p>I looked these words up and they all check out. See the <a href="http://www.hasbro.com/scrabble/home.cfm">Scrabble dictionary</a> if you&#8217;re not convinced.</p>
<p>How many words can we expect to find on each board?</p>
<p><center><img src='http://www.danvk.org/wp/wp-content/uploads/2007/02/words.png' alt='words.png' /></center></p>
<p>That looks like a <a href="http://en.wikipedia.org/wiki/Log-normal_distribution">log-normal distribution</a>. The mean is 98.53 words. How many points?</p>
<p><center><img src='http://www.danvk.org/wp/wp-content/uploads/2007/02/scores.png' alt='scores.png' /></center></p>
<p>That&#8217;s also a log-normal distribution with the characteristically long tail. The mean is 140.97 points per board.</p>
<p>How many words of each length can we expect to find on a board? Here&#8217;s a histogram of the number of words of each length on a board:</p>
<p><center><img src='http://www.danvk.org/wp/wp-content/uploads/2007/02/lens.png' alt='lens.png' /></center></p>
<p>Those also look like log-normals, with four letter words being most common.</p>
<p>Put another way, what&#8217;s the likelihood of finding a word of a given length on a board?</p>
<table>
<tr>
<th>Len.</th>
<th>Likelihood</th>
</tr>
<tr>
<td>3</td>
<td>99.97994%</td>
</tr>
<tr>
<td>4</td>
<td>99.901%</td>
</tr>
<tr>
<td>5</td>
<td>98.62%</td>
</tr>
<tr>
<td>6</td>
<td>87.56%</td>
</tr>
<tr>
<td>7</td>
<td>56.21%</td>
</tr>
<tr>
<td>8</td>
<td>21.36%</td>
</tr>
<tr>
<td>9</td>
<td>3.94%</td>
</tr>
<tr>
<td>10</td>
<td>0.442%</td>
</tr>
<tr>
<td>11</td>
<td>0.0362%</td>
</tr>
<tr>
<td>12</td>
<td>0.00228%</td>
</tr>
<tr>
<td>13</td>
<td>0.0001%</td>
</tr>
</table>
<p>For context, the longest word I&#8217;ve ever found in a game was &#8220;thrashers&#8221; at nine letters.</p>
<p>The most common words were based on a 50,000 board sample. The graphs are based on a 5,000,000 board sample. Feel free to contact me if you&#8217;d like source or the Excel spreadsheet.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.danvk.org/wp/2007-02-11/some-boggle-statistics/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

