<?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>Master Baboon</title>
	<atom:link href="http://www.masterbaboon.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.masterbaboon.com</link>
	<description>The sea of the simulation</description>
	<lastBuildDate>Sun, 01 Apr 2012 08:36:48 +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>Cobol for LISP developers</title>
		<link>http://www.masterbaboon.com/2012/03/cobol-for-lisp-developers/</link>
		<comments>http://www.masterbaboon.com/2012/03/cobol-for-lisp-developers/#comments</comments>
		<pubDate>Sat, 31 Mar 2012 17:50:25 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[fun]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=597</guid>
		<description><![CDATA[Given the proliferation of "X for Y developers" books, I decided to collect some information to help me find a niche for my own book! This table shows the number of combined Google hits for "X for Y developers" and "X for Y programmers", with a selection of Xs and Ys (e.g., the first rows [...]]]></description>
			<content:encoded><![CDATA[<p>Given the proliferation of "X for Y developers" books, I decided to collect some information to help me find a niche for my own book!</p>
<p>This table shows the number of combined Google hits for "X for Y developers" and "X for Y programmers", with a selection of Xs and Ys (e.g., the first rows shows the hits for "BASIC for BASIC developers", "BASIC for C++ developers", etc.):</p>
<p style="text-align: center;"><a href="http://www.masterbaboon.com/wp-content/uploads/2012/03/X_for_Y_devs_table2.jpg"><img class="aligncenter  wp-image-616" title="X_for_Y_devs_table" src="http://www.masterbaboon.com/wp-content/uploads/2012/03/X_for_Y_devs_table2.jpg" alt="" width="514" height="529" /></a></p>
<p style="text-align: left;">It looks like we're missing a good "Cobol for BASIC programmers" book: I'll start typing right away!</p>
<p style="text-align: left;">Note that the matrix is highly asymmetric: apparently, Perl programmers are more interested to switch to Python than vice versa. We can turn the entries of the matrix into weights in a directed graph, that can be loosely interpreted as the relative number of people that would like to switch from a programming language to another. Below you can see the graphs for six of the languages (the size of the arrows correspond to one of 6 bins of equal size on a logarithmic scale; no arrow means zero results):</p>
<p style="text-align: left;"><a href="http://www.masterbaboon.com/wp-content/uploads/2012/03/X_for_Y_devs_arrows.jpg"><img class="aligncenter  wp-image-599" title="X_for_Y_devs_arrows" src="http://www.masterbaboon.com/wp-content/uploads/2012/03/X_for_Y_devs_arrows.jpg" alt="" width="522" height="661" /></a></p>
<p style="text-align: left;">In case you were wondering: yes, there really is a successful <a href="http://www.amazon.com/Java-COBOL-Programmers-Programming-Series/dp/1584505656/ref=dp_ob_title_bk" target="_blank">"Java for Cobol programmers" book</a>!</p>
<p style="text-align: left;"><strong>Update </strong>1 Apr 2012: <em>Added values for Fortran to the table.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2012/03/cobol-for-lisp-developers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Open-ended evolution in ALife</title>
		<link>http://www.masterbaboon.com/2012/03/open-ended-evolution-in-alife/</link>
		<comments>http://www.masterbaboon.com/2012/03/open-ended-evolution-in-alife/#comments</comments>
		<pubDate>Wed, 21 Mar 2012 21:19:54 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Artificial Life]]></category>
		<category><![CDATA[ALife]]></category>
		<category><![CDATA[open-ended evolution]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=565</guid>
		<description><![CDATA[The concept of "open-ended evolution" in artificial life is mostly misunderstood. In many cases, "open-ended" is taken to mean that the final solution can take any shape, however complicated. Instead, a stronger definition of "open-ended" would require that the fitness function itself is changing. For example, Genetic Programming would be defined as open-ended in the [...]]]></description>
			<content:encoded><![CDATA[<p>The concept of "open-ended evolution" in artificial life is mostly misunderstood. In many cases, "open-ended" is taken to mean that the final solution can take any shape, however complicated. Instead, a stronger definition of "open-ended" would require that the fitness function itself is changing. For example, Genetic Programming would be defined as open-ended in the first sense, since the evolved programs can solve and computable problem (provided that the instruction set is Turing-complete), but is not in the second sense, as the programs are selected according to one, immutable fitness function. This is more akin to adaptation than evolution.</p>
<p>In my opinion, an important but neglected goal of ALife should be that of identifying a minimal set of conditions that is able to sustain this stronger kind of open-ended evolution.</p>
<p>What would it take for an artificial system to display "real" open-ended evolution? It is possible that there may be multiple answer to this question, but co-evolution of agents seems to be a good candidate. A minimal example might involve populations of agents trying to predict each other's output. The output of a population should be tied to the process of predicting the response of the others. To initiate a runaway evolution process, predicting a simple output should require a simple algorithm, which however would produce a slightly more complex output by the laws of the artificial world. In such a scenario, the fitness function is given by the combination of prediction algorithms in the population, and <em>each evolutionary step changes it in a way that requires increasingly complex behaviors</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2012/03/open-ended-evolution-in-alife/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Warning: time sink! Or: the latest Google AI challenge</title>
		<link>http://www.masterbaboon.com/2011/11/warning-time-sink-or-the-latest-google-ai-challenge/</link>
		<comments>http://www.masterbaboon.com/2011/11/warning-time-sink-or-the-latest-google-ai-challenge/#comments</comments>
		<pubDate>Fri, 11 Nov 2011 08:38:44 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[games]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=559</guid>
		<description><![CDATA[It's that time of the year again... the word spreads, I download it, and my nights fly by. It's time for the new Google AI Challenge: http://aichallenge.org/ ! This time we will be writing multi-agent systems, as we program cyber-ant-colonies fighting against each other for bread crumbs.]]></description>
			<content:encoded><![CDATA[<blockquote><p>It's that time of the year again... the word spreads, I download it, and my nights fly by. It's time for the new <strong>Google AI Challenge</strong>: <a href="http://aichallenge.org/">http://aichallenge.org/</a> ! This time we will be writing multi-agent systems, as we program cyber-ant-colonies fighting against each other for bread crumbs.</p>
<div id="attachment_560" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.masterbaboon.com/wp-content/uploads/2011/11/GoogleAIChallenge_ants.png"><img class="size-medium wp-image-560" title="AI challenge screenshot: ants!" src="http://www.masterbaboon.com/wp-content/uploads/2011/11/GoogleAIChallenge_ants-300x289.png" alt="" width="300" height="289" /></a><p class="wp-caption-text">The colored dots are ants of different colonies. The black dots are obstacles. The barely visible brown-ish dots are food.</p></div></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2011/11/warning-time-sink-or-the-latest-google-ai-challenge/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The road to javascript</title>
		<link>http://www.masterbaboon.com/2011/06/the-road-to-javascript/</link>
		<comments>http://www.masterbaboon.com/2011/06/the-road-to-javascript/#comments</comments>
		<pubDate>Wed, 29 Jun 2011 13:06:53 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=547</guid>
		<description><![CDATA[I wanted to learn javascript and wrote a small game with an old school look using textareas, that I'm glad to share: Writing javascript is quite intuitive for a Python developer, even though I'm sure that there are many idioms and tricks that I did not know about (and the code I wrote is the [...]]]></description>
			<content:encoded><![CDATA[<p>I wanted to learn javascript and wrote a <a href="http://www.masterbaboon.com/brum/" target="_blank">small game</a> with an old school look using textareas, that I'm glad to share:</p>
<div id="attachment_548" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.masterbaboon.com/brum/"><img class="size-medium wp-image-548" title="brum_screenshot" src="http://www.masterbaboon.com/wp-content/uploads/2011/06/brum_screenshot-300x300.jpg" alt="A screenshot of the game" width="300" height="300" /></a><p class="wp-caption-text">A screenshot of the game</p></div>
<p>Writing javascript is quite intuitive for a Python developer, even though I'm sure that there are many idioms and tricks that I did not know about (and the code I wrote is the stream-of-thought kind).  I'm somewhat disappointed as I thought javascript would be more standard across browsers, but there remain important differences, for example in the way Firefox and IE handle ranges in textarea.</p>
<p>I haven't tried the game on Safari or Opera, please let me know if it works!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2011/06/the-road-to-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Games with extensible AI</title>
		<link>http://www.masterbaboon.com/2011/06/games-with-extensible-ai/</link>
		<comments>http://www.masterbaboon.com/2011/06/games-with-extensible-ai/#comments</comments>
		<pubDate>Sun, 05 Jun 2011 00:01:06 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[games]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=501</guid>
		<description><![CDATA[Some computer games offer the possibility to extend their Artificial Intelligence with external scripts, or are explicitly designed to be played by bots. Such games are a great resource to develop, test, and teach AI algorithms. I have been looking for a list of this kind of games, but could find very little information, often [...]]]></description>
			<content:encoded><![CDATA[<p>Some computer games offer the possibility to extend their Artificial Intelligence with external scripts, or are explicitly designed to be played by bots. Such games are a great resource to develop, test, and teach AI algorithms.</p>
<p>I have been looking for a list of this kind of games, but could find very little information, often outdated. This is my own, annotated list; let me know if I missed something, and I'll make amend. I included only decently active projects:</p>
<p><strong>Games for bots:</strong></p>
<ol>
<li><strong><a href="http://robocode.sourceforge.net/" target="_blank">Robocode</a> (Java, .NET)</strong>: AI bots control tanks equipped with cannon and radar on an square arena. A game with a long tradition, descending from the classic AI games <a href="http://en.wikipedia.org/wiki/RobotWar" target="_blank">RobotWar </a>(1981) and <a href="http://en.wikipedia.org/wiki/Crobots" target="_blank">crobots </a>(1985). This is a very active project, with tournaments organized regularly all over the world. The strategical possibilities are quite limited, though.</li>
<li><strong><a href="http://csclub.uwaterloo.ca/contest/">Tron</a> challenge (any language)</strong>: This is the first AI competition organized by the <a href="http://csclub.uwaterloo.ca/" target="_blank">University of Waterloo Computer Science Club</a> and sponsored by Google. The AIs control the "snakes" in a variant of the popular game <a href="http://en.wikipedia.org/wiki/Snake_%28video_game%29">Snake</a> (or <a href="http://en.wikipedia.org/wiki/Nibbles_%28video_game%29">Nibbles</a>, of QBasic fame) on a number of boards with symmetric walls. Although the competition is closed, the code is open source and perfectly usable. A nice game, but there seems to be one dominating strategy: using minimax. Entries in the competition differ in their cleverness in coming up with various approximations to prune down the huge tree of possible  moves, and in handling the endgame.</li>
<li><strong><a href="http://ai-contest.com/" target="_blank">Planet Wars</a> challenge (any language)</strong>: Second AI competition, again organized by the <a href="http://csclub.uwaterloo.ca/" target="_blank">University of Waterloo CS Club</a>. The inspiration is the galactic conquer game <a href="http://www.galcon.com/games/?action=game&amp;name=igalcon" target="_blank">Galcon</a>. Bots controls fleets of spaceships to control planets for resources. Unlike the first competition, the optimal strategy is far from obvious, and the game offers a lot of space for experimenting with different approaches. Not as visually fun as other games, though.</li>
<li><strong><a href="http://inst.eecs.berkeley.edu/~cs188/pacman/projects/contest/contest.html">PacMan capture the flag</a> (Python)</strong>: The CS department at Berkeley offers a very popular <a href="http://inst.eecs.berkeley.edu/~cs188/sp11/information.html" target="_blank">Artificial Intelligence course</a> that requires students to <a href="http://inst.eecs.berkeley.edu/~cs188/pacman/pacman.html" target="_blank">code up classical AI algorithms</a> to control agents in a PacMan-like environment. The course concludes with a <a href="http://inst.eecs.berkeley.edu/~cs188/pacman/projects/contest/contest.html" target="_blank">tournament </a>in which PacMan agents compete to eat each other's dots. The game is extremely fun as I wrote about <a href="http://www.masterbaboon.com/2009/09/pacman-capture-the-flag-a-fun-game-for-artificial-intelligence-development-and-education/" target="_self">in</a> <a href="http://www.masterbaboon.com/2010/09/tracking-down-the-enemy/" target="_self">previous</a> <a href="http://www.masterbaboon.com/2011/01/tracking-down-the-enemy-2/">posts</a>. The code is <a href="http://inst.eecs.berkeley.edu/~cs188/pacman/projects/contest/contest.html" target="_blank">available online</a> (although somewhat messy). Unfortunately (but understandably, since the game is used in a course), the authors don't want the code of developed agents to leak online.</li>
<li><strong><a href="http://gridsoccer.codeplex.com/" target="_blank">Grid-Soccer</a> (Mono, .NET):</strong> This is a multi-agent soccer-like game played on a grid board. I haven't tried this one yet... According to the authors, it was originally conceived as a testbed for multi-agent reinforcement learning algorithms.</li>
</ol>
<p><strong>Scriptable games</strong> (games that expose an interface for external clients):</p>
<ol>
<li><strong><a href="http://en.wikipedia.org/wiki/StarCraft:_Brood_War" target="_blank">Starcraft Brood War</a> (any language): </strong>This is your one chance at writing AI bots for a commercial game! <img src='http://www.masterbaboon.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  Starcraft <a href="http://code.google.com/p/bwapi/" target="_blank">has been hacked</a> to allow to control any aspect of the game through a user-written client (building construction, units movement, the full monty). Since 2010 there have been a few <a href="http://code.google.com/p/bwapi/wiki/Competitions#AIIDE_2011" target="_blank">AI competitions</a> open to the public (two of them still accepting entries!). Here's a video from last year's <a href="http://eis.ucsc.edu/StarCraftAICompetition" target="_blank">AIIDE tournament</a>:
<p><iframe width="544" height="327" src="http://www.youtube.com/embed/2rqpz2GU9GU" frameborder="0" allowfullscreen></iframe></li>
<li><strong><a href="http://xblast.sourceforge.net/" target="_blank">XBlast (potentially any):</a> </strong>A free version of <a href="http://en.wikipedia.org/wiki/Bomberman" target="_blank">Bomberman</a>. The game has not been used to develop AI agents... yet. It is built with a server-client architecture and it's begging to get bots running on it.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2011/06/games-with-extensible-ai/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Evolve a Dune Buggy</title>
		<link>http://www.masterbaboon.com/2011/05/evolve-a-dune-buggy/</link>
		<comments>http://www.masterbaboon.com/2011/05/evolve-a-dune-buggy/#comments</comments>
		<pubDate>Sun, 15 May 2011 14:46:08 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Artificial Life]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=486</guid>
		<description><![CDATA[Natural selection is the algorithm Nature uses to maximize the probability of reproduction of organisms. With Genetic Algorithms (GAs), engineers imitate this process in order to optimize a set of parameters in an engineering problem... or a dune buggy! The great application at boxcar2d.com uses simulated physics to evolve 2D cars that are optimally fast [...]]]></description>
			<content:encoded><![CDATA[<p>Natural selection is the algorithm Nature uses to maximize the probability of reproduction of organisms. With Genetic Algorithms (GAs), engineers imitate this process in order to optimize a set of parameters in an engineering problem... or<a href="http://www.boxcar2d.com/index.html" target="_blank"> a dune buggy</a>! The great application at boxcar2d.com uses simulated physics to evolve 2D cars that are optimally fast and stable.</p>
<div id="attachment_506" class="wp-caption aligncenter" style="width: 215px"><img class="size-medium wp-image-506" title="evolved_car" src="http://www.masterbaboon.com/wp-content/uploads/2011/05/gilgenk1-300x205.gif" alt="evolved_car" width="205" height="140" /><p class="wp-caption-text">Example of an evolved car.</p></div>
<p style="text-align: center;">
<p>GAs tie the ability to solve a problem to the likelihood of reproduction of a set of parameters: first, one creates a population of possible solutions to a problem, evaluates  the solutions, and then forms a new generation by allowing the most  successful ones to pass their parameters to the next generation, after  small mutations and parameters swapping.</p>
<p>My general feeling about GAs is that in most cases other optimization algorithms will give similar or better results with less evaluations of the fitness function (which is typically the bottleneck). In Chapter 30.2 of his <a href="http://www.inference.phy.cam.ac.uk/mackay/itila/" target="_blank">classic book on information theory</a>, David McKay gives a very interesting interpretation of GAs as a Monte Carlo sampling in the space of parameters, and discusses the relation with efficient sampling methods, of which we have a better formal understanding.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2011/05/evolve-a-dune-buggy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fight the machine at NYT</title>
		<link>http://www.masterbaboon.com/2011/03/fight-the-machine-at-nyt/</link>
		<comments>http://www.masterbaboon.com/2011/03/fight-the-machine-at-nyt/#comments</comments>
		<pubDate>Sat, 05 Mar 2011 22:41:28 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[AI]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=496</guid>
		<description><![CDATA[Perhaps inspired by the victory of the artificial brain Watson against humanity, the New York Times is offering today an interactive feature that allows to play a series of Rock-Paper-Scissors games against the computer. The prediction algorithm seems to be a simple Bayesian estimator like the one I implemented for the Karate A.I. game. The [...]]]></description>
			<content:encoded><![CDATA[<p>Perhaps inspired by the <a href="http://en.wikipedia.org/wiki/Watson_%28artificial_intelligence_software%29" target="_blank">victory of the artificial brain Watson against humanity</a>, the New York Times is offering today an interactive feature that allows to play a series of <a href="http://www.nytimes.com/interactive/science/rock-paper-scissors.html" target="_blank">Rock-Paper-Scissors games</a> against the computer.</p>
<p>The prediction algorithm seems to be a simple Bayesian estimator like the one I implemented for the <a href="http://www.masterbaboon.com/2009/05/my-ai-reads-your-mind-and-kicks-your-ass-part-2/">Karate A.I. game</a>. The interesting twist is that in "Veteran mode" the AI will make use its interaction with previous users to define a prior over possible move sequences. It surely works against me...</p>
<p style="text-align: center;"><a href="http://www.nytimes.com/interactive/science/rock-paper-scissors.html"><img class="aligncenter" title="NYT man vs machine" src="http://graphics8.nytimes.com/images/2011/03/04/science/rock-paper-scissors.190.jpg" alt="" width="190" height="126" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2011/03/fight-the-machine-at-nyt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Join us at the Advanced Scientific Programming in Python summer school in Scotland</title>
		<link>http://www.masterbaboon.com/2011/03/join-us-at-the-advanced-scientific-programming-in-python-summer-school-in-scotland/</link>
		<comments>http://www.masterbaboon.com/2011/03/join-us-at-the-advanced-scientific-programming-in-python-summer-school-in-scotland/#comments</comments>
		<pubDate>Thu, 03 Mar 2011 17:31:17 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Education]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[PacMan]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=489</guid>
		<description><![CDATA[If you're interested in learning more about scientific programming in Python, and want to compete in a Pacman capture-the-flag tournament, join us for the next Advanced Scientific Programming in Python summer school in St. Andrew, UK! The faculty line-up includes developers of well-known scientific libraries for Python (e.g., Francesc Alted of PyTables fame). The program [...]]]></description>
			<content:encoded><![CDATA[<p>If you're interested in learning more about scientific programming in Python, and want to compete in a <a href="http://www.masterbaboon.com/2009/09/pacman-capture-the-flag-a-fun-game-for-artificial-intelligence-development-and-education/">Pacman</a> <a href="http://www.masterbaboon.com/2010/09/tracking-down-the-enemy/">capture-the-flag</a> <a href="http://www.masterbaboon.com/2011/01/tracking-down-the-enemy-2/">tournament</a>, join us for the next <a href="https://python.g-node.org/wiki/">Advanced Scientific Programming in Python</a> summer school in St. Andrew, UK!</p>
<p>The faculty line-up includes developers of well-known scientific libraries for Python (e.g., <a href="http://www.pytables.org/moin/FrancescAlted">Francesc Alted</a> of <a href="http://www.pytables.org/moin">PyTables</a> fame). The program covers advanced topics in numerical programming (advanced NumPy, Cython, parallel applications, data serialization, ...) and modern techniques for writing robust, efficient code (agile programming, test driven development, version control, optimization techniques, ...). Most of all, the school is a great opportunity to meet like-minded people and have fun writing Python code together! Participation is free of charge, and you can <a href="https://python.g-node.org/wiki/">apply online</a>.</p>
<p>You can see a few picture from previous summer schools on our<a href="http://www.facebook.com/group.php?gid=145875921776" target="_blank"> Facebook group</a>.</p>
<p style="text-align: center;">
<div class="wp-caption aligncenter" style="width: 372px"><img class=" " title="Summer school in Berlin" src="http://a5.sphotos.ak.fbcdn.net/hphotos-ak-snc1/6830_1201852400426_1052055109_608170_5509474_n.jpg" alt="Summer school participants in Berlin, working hard on their PacMan agents." width="362" height="243" /><p class="wp-caption-text">Summer school participants in Berlin, working hard on their PacMan agents.</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2011/03/join-us-at-the-advanced-scientific-programming-in-python-summer-school-in-scotland/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tracking down the enemy (2)</title>
		<link>http://www.masterbaboon.com/2011/01/tracking-down-the-enemy-2/</link>
		<comments>http://www.masterbaboon.com/2011/01/tracking-down-the-enemy-2/#comments</comments>
		<pubDate>Fri, 21 Jan 2011 23:39:42 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[PacMan]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=456</guid>
		<description><![CDATA[I never got the chance to show a working agent based on the Bayesian estimator for the enemy position in the PacMan capture-the-flag game. In the previous PacMan post, I wrote about merging a model of agent movements with the noisy measurements returned by the game to track the enemy agents across the maze. Clearly, [...]]]></description>
			<content:encoded><![CDATA[<p>I never got the chance to show a working agent based on the Bayesian estimator for the enemy position in the PacMan capture-the-flag game. In the <a href="http://www.masterbaboon.com/2010/09/tracking-down-the-enemy/" target="_self">previous PacMan post</a>, I wrote about merging a model of agent movements with the noisy measurements returned by the game to track the enemy agents across the maze. Clearly, this information can give you an edge when planning an attack (to avoid ghosts) or when defending (to intercept the PacMen).</p>
<p>For  the traditional faculty-vs-students tournament at the <a href="https://portal.g-node.org/python-autumnschool/" target="_blank">G-Node scientific programming summer school</a> this year, I wrote a PacMan team made by a simple attacker, and a more sophisticated defender that tries to intercept and devour enemy agents.</p>
<p>Both agents plan their movements using a shortest-path algorithm on a weighted graph: before the start of the game, the maze is transformed in a graph, where nodes are the maze tiles, and edges connect adjacent tiles. Weights along the edges are adjusted according to the estimated position of the agents:</p>
<ul>
<li>Weights on edges close to an enemy ghost are increased (starting value is proportional to the probability of the enemy being there, and falls off exponentially with distance)</li>
<li>Weights on edges close to an enemy PacMan are decreased</li>
<li>Weights on edges close to a friendly agent are increased</li>
</ul>
<p>An agent navigating on such a maze will tend to avoid ghosts, chase PacMen, and cover parts of the maze far from other friendly agents. My attacker does little else than updating the weights of the graph at every turn, and move toward the closest food dot.</p>
<p>On the other hand, defending is quite difficult in this game, so I needed a more sophisticated strategy. While the enemy is still a ghost in its own part of the maze, the defender moves toward the closest enemy agent (its estimated position, that is). When the enemy is a PacMan in the friendly half, the chase is on! Since ghosts and PacMen move at the same speed, it would be pointless to just follow it around, one needs to catch them from the front... Once more, the solution was to modify the weights of the maze graph, making weights behind the enemy (i.e., opposite to its direction of motion) very high, and lowering the edges in front of it.</p>
<p>The combination of estimator and the weighted graph strategy can be quite entertaining:</p>
<p><iframe title="YouTube video player" type="text/html" width="544" height="327" src="http://www.youtube.com/embed/YM-rQJPL16o" frameborder="0" allowFullScreen></iframe></p>
<p>Sometimes the defender only needs to guard the border to scare the opponent shitless:</p>
<p><iframe title="YouTube video player" class="youtube-player" type="text/html" width="544" height="327" src="http://www.youtube.com/embed/1ciCtwW14RY" frameborder="0" allowFullScreen></iframe></p>
<p>Another useful thing to keep in mind for the future: it is better to base strategies on soft constraints (weighted graphs, probabilities). Setting hard, deterministic rules tends to get you stuck in loops. Soft constraints and some randomness give you more flexibility when you need it but are otherwise just as good.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2011/01/tracking-down-the-enemy-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Solving the game Set®</title>
		<link>http://www.masterbaboon.com/2010/09/solving-the-game-set/</link>
		<comments>http://www.masterbaboon.com/2010/09/solving-the-game-set/#comments</comments>
		<pubDate>Wed, 15 Sep 2010 14:58:05 +0000</pubDate>
		<dc:creator>pietro</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[games]]></category>

		<guid isPermaLink="false">http://www.masterbaboon.com/?p=292</guid>
		<description><![CDATA[Recently a friend of mine introduced me to a game called Set. Set is a logic cards game for several players; 3-5 players is probably best, but in there is no limit in principle, and it is also fun to play as a solitary. The game contains a deck of cards with symbols varying across [...]]]></description>
			<content:encoded><![CDATA[<p>Recently a friend of mine introduced me to a game called <em><a href="http://www.setgame.com/set/index.html">Set</a></em>. <em>Set </em>is a logic cards game for several players; 3-5 players is probably best, but in there is no limit in principle, and it is also fun to play as a solitary.</p>
<p>The game contains a deck of cards with symbols varying across 4 dimensions: color, number, shape, and texture. For each dimension, there are 3 possible features (e.g., there are 3 possible textures: full, empty, striped). A valid <em>set</em> is formed by three cards that have on each dimension either the <em>same</em> feature, or <em>three different</em> features. So for example in the image below, the first three cards are a valid set, as they are different on all features across all dimensions; the second three cards also form a valid set, because they share the same features for color and number, and are different in shape and texture; the cards on the bottom are not a set, because two cards have the "full" texture, while one is striped.</p>
<p style="text-align: center;">
<div id="attachment_445" class="wp-caption aligncenter" style="width: 410px"><img class="size-large wp-image-445 " title="sets_examples" src="http://www.masterbaboon.com/wp-content/uploads/2010/09/sets_examples1-1024x586.png" alt="Example of valid (top) and invalid (bottom) sets." width="400" height="229" /><p class="wp-caption-text">Example of valid (top) and invalid (bottom) sets.</p></div>
<p>In a Set game, 12 cards are put on the table, and the players have to find a valid set. The quickest among them collects the set and replaces the removed cards with new ones. If the players agree that there is no set on the table, 3 more cards are added. Once the deck is empty, the player who collected the most sets wins! Simple but fun...</p>
<p>I decided to write a solver for the game that finds all possible sets given a set of cards, with the goal of collecting statistics over thousands of games. The solver should thus be as efficient as I can manage to write it.</p>
<p>I'm going to represent each cards as a four-dimensional vector (color, shape, texture, number), each element containing either 0, 1, or 2 (representing the 3 possible values for each dimension). A function that checks if three cards form a valid set would thus look like this:</p>
<pre style="font: normal normal normal 12px/18px Consolas, Monaco, 'Courier New', Courier, monospace;">
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> numpy<br />
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">itertools</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> same<span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;&quot;&quot;Returns True if all elements are the same.&quot;&quot;&quot;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> numpy.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span>x <span style="color: #66cc66;">==</span> x<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> different<span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;&quot;&quot;Returns True if all elements are different.&quot;&quot;&quot;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>numpy.<span style="color: black;">unique</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> is_set<span style="color: black;">&#40;</span>cards<span style="color: #66cc66;">,</span> indices<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;&quot;&quot;Checks that the cards indexed by 'indices' form a valid set.&quot;&quot;&quot;</span><br />
&nbsp; &nbsp; ndims <span style="color: #66cc66;">=</span> cards.<span style="color: black;">shape</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br />
<br />
&nbsp; &nbsp; subset <span style="color: #66cc66;">=</span> cards<span style="color: black;">&#91;</span>:<span style="color: #66cc66;">,</span> indices<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> dim <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>ndims<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># cards must be all the same or all different for all dimensions</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> same<span style="color: black;">&#40;</span>subset<span style="color: black;">&#91;</span>dim<span style="color: #66cc66;">,</span> :<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #ff7700;font-weight:bold;">not</span> different<span style="color: black;">&#40;</span>subset<span style="color: black;">&#91;</span>dim<span style="color: #66cc66;">,</span> :<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span></div></td></tr></tbody></table></div>
</pre>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># solution checker</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># ----------------</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def same(x):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Returns True if all elements are the same."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return numpy.all(x == x[0])</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def different(x):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Returns True if all elements are different."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return len(numpy.unique(x)) == len(x)</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def is_set(cards, indices):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Checks that the cards indexed by 'indices' form a valid set."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">ndims = cards.shape[0]</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">subset = cards[:, indices]</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">for dim in range(ndims):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># cards must be all the same or all different for all dimensions</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">if not same(subset[dim, :]) and not different(subset[dim, :]):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return False</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return True</div>
<div>A brute force solver could then try all possible combinations of three cards and check whether they form a valid set:</div>
<pre style="font: normal normal normal 12px/18px Consolas, Monaco, 'Courier New', Courier, monospace;">
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> find_sets<span style="color: black;">&#40;</span>cards<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;&quot;&quot;Brute-force Sets solver.&quot;&quot;&quot;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span>indices<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> indices <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">itertools</span>.<span style="color: black;">combinations</span><span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span>cards.<span style="color: black;">shape</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> is_set<span style="color: black;">&#40;</span>cards<span style="color: #66cc66;">,</span> indices<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span></div></td></tr></tbody></table></div>
</pre>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># solution checker</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># ----------------</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def same(x):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Returns True if all elements are the same."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return numpy.all(x == x[0])</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def different(x):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Returns True if all elements are different."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return len(numpy.unique(x)) == len(x)</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def is_set(cards, indices):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Checks that the cards indexed by 'indices' form a valid set."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">ndims = cards.shape[0]</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">subset = cards[:, indices]</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">for dim in range(ndims):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># cards must be all the same or all different for all dimensions</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">if not same(subset[dim, :]) and not different(subset[dim, :]):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return False</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return True</div>
<p>The brute force approach is very inefficient, but it is also very useful to test more efficient solutions (just check that they give the same response as the brute force one).</p>
<p>The second solver improves on the first one with a simple observation. Once you have two cards, there is only one possible card that completes the set: for each dimension, if the two cards have the same feature, the missing one will also have to have the same feature; if the features are different, the missing card will have to have the missing feature.</p>
<p style="text-align: center;">
<div id="attachment_446" class="wp-caption aligncenter" style="width: 410px"><img class="size-full wp-image-446  " title="complete_set" src="http://www.masterbaboon.com/wp-content/uploads/2010/09/complete_set1.png" alt="Given two cards, there is only one possible card that forms a valid set." width="400" height="234" /><p class="wp-caption-text">Given two cards, there is only one possible card that forms a valid set.</p></div>
<p>A possible strategy is thus to consider all possible pairs of cards, derive the one completing the set, and check if it is present on the table. This solution is much more efficient, as there are 220 possible triplets out of 12 cards, but only 66 pairs. It runs about 6 times faster:</p>
<pre style="font: normal normal normal 12px/18px Consolas, Monaco, 'Courier New', Courier, monospace;">
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> find_sets2<span style="color: black;">&#40;</span>cards<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; ndims<span style="color: #66cc66;">,</span> ncards <span style="color: #66cc66;">=</span> cards.<span style="color: black;">shape</span><br />
&nbsp; &nbsp; all_features <span style="color: #66cc66;">=</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># solutions contain the indices of the cards forming sets</span><br />
&nbsp; &nbsp; solutions <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># iterate over all pairs</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> idx1<span style="color: #66cc66;">,</span> idx2 <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">itertools</span>.<span style="color: black;">combinations</span><span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span>ncards - <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; c1<span style="color: #66cc66;">,</span> c2 <span style="color: #66cc66;">=</span> cards<span style="color: black;">&#91;</span>:<span style="color: #66cc66;">,</span> idx1<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> cards<span style="color: black;">&#91;</span>:<span style="color: #66cc66;">,</span> idx2<span style="color: black;">&#93;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># compute card that would complete the set</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; missing <span style="color: #66cc66;">=</span> numpy.<span style="color: black;">empty</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>ndims<span style="color: #66cc66;">,</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> dtype<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'i'</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> d <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>ndims<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> c1<span style="color: black;">&#91;</span>d<span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> c2<span style="color: black;">&#91;</span>d<span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># same feature on this dimension -&gt;; missing card also has same</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; missing<span style="color: black;">&#91;</span>d<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> c1<span style="color: black;">&#91;</span>d<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># different features -&gt; find third missing feature</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; missing<span style="color: black;">&#91;</span>d<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>all_features - <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>c1<span style="color: black;">&#91;</span>d<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> c2<span style="color: black;">&#91;</span>d<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># look for missing card in the cards array</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; where_idx <span style="color: #66cc66;">=</span> numpy.<span style="color: black;">flatnonzero</span><span style="color: black;">&#40;</span>numpy.<span style="color: #008000;">all</span><span style="color: black;">&#40;</span>cards<span style="color: black;">&#91;</span>:<span style="color: #66cc66;">,</span> idx2 + <span style="color: #ff4500;">1</span>:<span style="color: black;">&#93;</span>.<span style="color: black;">T</span> <span style="color: #66cc66;">==</span> missing<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; axis<span style="color: #66cc66;">=</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># append to solutions if found</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>where_idx<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; solutions.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>idx1<span style="color: #66cc66;">,</span> idx2<span style="color: #66cc66;">,</span> where_idx<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> + idx2 + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> solutions</div></td></tr></tbody></table></div>
</pre>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># solution checker</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># ----------------</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def same(x):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Returns True if all elements are the same."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return numpy.all(x == x[0])</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def different(x):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Returns True if all elements are different."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return len(numpy.unique(x)) == len(x)</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def is_set(cards, indices):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Checks that the cards indexed by 'indices' form a valid set."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">ndims = cards.shape[0]</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">subset = cards[:, indices]</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">for dim in range(ndims):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># cards must be all the same or all different for all dimensions</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">if not same(subset[dim, :]) and not different(subset[dim, :]):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return False</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return True</div>
<p>The trained eye will see at this point that the problem can be re-written as a dynamic programming one. We can start looking at the first dimension, and form groups of cards with the same feature. We know by the reasoning above that valid sets will either contain cards in the same group, or contain one card from each group. First we consider the former case, and recursively apply the same procedure to all the remaining dimensions for cards within each group. Second, we consider all triplets of cards that have one card per group and verify if it's a set:</p>
<pre style="font: normal normal normal 12px/18px Consolas, Monaco, 'Courier New', Courier, monospace;">
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> find_sets3<span style="color: black;">&#40;</span>cards<span style="color: #66cc66;">,</span> indices<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; nd<span style="color: #66cc66;">,</span> n <span style="color: #66cc66;">=</span> cards.<span style="color: black;">shape</span><br />
&nbsp; &nbsp; c0 <span style="color: #66cc66;">=</span> cards<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> :<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> indices <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; indices <span style="color: #66cc66;">=</span> numpy.<span style="color: black;">arange</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; groups <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>c0 <span style="color: #66cc66;">==</span> f<span style="color: black;">&#41;</span>.<span style="color: black;">nonzero</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> f <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>nfeatures<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># equals</span><br />
&nbsp; &nbsp; solequal <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> g <span style="color: #ff7700;font-weight:bold;">in</span> groups:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>g<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">3</span>: <span style="color: #ff7700;font-weight:bold;">continue</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; solequal +<span style="color: #66cc66;">=</span> find_sets3<span style="color: black;">&#40;</span>cards<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>:nd<span style="color: #66cc66;">,</span> g<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> indices<span style="color: black;">&#91;</span>g<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># different</span><br />
&nbsp; &nbsp; soldiff <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>indices<span style="color: black;">&#91;</span>i0<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> indices<span style="color: black;">&#91;</span>i1<span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> indices<span style="color: black;">&#91;</span>i2<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #ff7700;font-weight:bold;">for</span> i0 <span style="color: #ff7700;font-weight:bold;">in</span> groups<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i1 <span style="color: #ff7700;font-weight:bold;">in</span> groups<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">for</span> i2 <span style="color: #ff7700;font-weight:bold;">in</span> groups<span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #ff7700;font-weight:bold;">if</span> is_set<span style="color: black;">&#40;</span>cards<span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span>i0<span style="color: #66cc66;">,</span> i1<span style="color: #66cc66;">,</span> i2<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> solequal + soldiff</div></td></tr></tbody></table></div>
</pre>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># solution checker</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># ----------------</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def same(x):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Returns True if all elements are the same."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return numpy.all(x == x[0])</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def different(x):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Returns True if all elements are different."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return len(numpy.unique(x)) == len(x)</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">def is_set(cards, indices):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">"""Checks that the cards indexed by 'indices' form a valid set."""</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">ndims = cards.shape[0]</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">subset = cards[:, indices]</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">for dim in range(ndims):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;"># cards must be all the same or all different for all dimensions</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">if not same(subset[dim, :]) and not different(subset[dim, :]):</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return False</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px; overflow: hidden;">return True</div>
<p>It turns out that, although it is a very efficient strategy to use  while playing with cards, find_sets3 is slower than  find_set2, probably because the overhead of calling the function  recursively outweighs the efficiency for such a small number of cards.</p>
<p>Let's have a look at some statistics, then. While playing it can be quite frustrating to stare at the cards without being able to find any set. The instructions that ship with the official game say that such a situation should occur only once every 33 turns, but it certainly doesn't feel that way. Is that really so?</p>
<p>First, I drew at random 12 cards from a complete deck of cards, and used the solver to compute the number of valid sets present on the table. I repeated this 10000 times, and ended up with this distribution for the number of set in a random draw:</p>
<div id="attachment_388" class="wp-caption aligncenter" style="width: 410px"><img class="size-full wp-image-388 " title="histogram_random_draws" src="http://www.masterbaboon.com/wp-content/uploads/2010/09/histogram_random_draws.png" alt="histogram_random_draws" width="400" height="248" /><p class="wp-caption-text">Probability of finding a given number of sets in 12 cards drawn at random.</p></div>
<p>As the instructions say, about 3% of the time (1 in 33) there is no set in the cards. However, this is misleading, as during a game the cards are not independently drawn each turn: the players remove one set from the cards on the table, and replace it with new cards. I thus simulated complete games, where at every turn I removed one of the set present on the table at random. The code to simulate a game look like this:</p>
<pre style="font: normal normal normal 12px/18px Consolas, Monaco, 'Courier New', Courier, monospace;">
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">def</span> random_deck<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># initialize cards deck</span><br />
&nbsp; &nbsp; cards <span style="color: #66cc66;">=</span> numpy.<span style="color: #dc143c;">array</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>card <span style="color: #ff7700;font-weight:bold;">for</span> card <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">itertools</span>.<span style="color: black;">product</span><span style="color: black;">&#40;</span><span style="color: #008000;">range</span><span style="color: black;">&#40;</span>nfeatures<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; repeat<span style="color: #66cc66;">=</span>ndims<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>.<span style="color: black;">T</span><br />
&nbsp; &nbsp; n <span style="color: #66cc66;">=</span> cards.<span style="color: black;">shape</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># shuffle</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> cards<span style="color: black;">&#91;</span>:<span style="color: #66cc66;">,</span> numpy.<span style="color: #dc143c;">random</span>.<span style="color: black;">permutation</span><span style="color: black;">&#40;</span>n<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
<br />
ncards <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">12</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> onegame<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; nsolutions <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; deck <span style="color: #66cc66;">=</span> random_deck<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; pos <span style="color: #66cc66;">=</span> ncards<br />
&nbsp; &nbsp; cards <span style="color: #66cc66;">=</span> deck<span style="color: black;">&#91;</span>:<span style="color: #66cc66;">,</span> :pos<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># find all sets</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">sets</span> <span style="color: #66cc66;">=</span> find_sets2<span style="color: black;">&#40;</span>cards<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; nsets <span style="color: #66cc66;">=</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">sets</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> nsets <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># choose a random set</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; chosen <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">sets</span><span style="color: black;">&#91;</span>numpy.<span style="color: #dc143c;">random</span>.<span style="color: black;">randint</span><span style="color: black;">&#40;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">sets</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># remove cards from chosen set</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; idx <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span>i <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>cards.<span style="color: black;">shape</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> i <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> chosen<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cards <span style="color: #66cc66;">=</span> cards<span style="color: black;">&#91;</span>:<span style="color: #66cc66;">,</span> idx<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># add new cards</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> cards.<span style="color: black;">shape</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">&lt;</span> <span style="color: #ff4500;">12</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nadd <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">12</span> - cards.<span style="color: black;">shape</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cards <span style="color: #66cc66;">=</span> numpy.<span style="color: black;">concatenate</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>cards<span style="color: #66cc66;">,</span> deck<span style="color: black;">&#91;</span>:<span style="color: #66cc66;">,</span> pos:pos + nadd<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> axis<span style="color: #66cc66;">=</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pos +<span style="color: #66cc66;">=</span> nadd<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> pos <span style="color: #66cc66;">&gt;=</span> deck.<span style="color: black;">shape</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">break</span> <span style="color: #808080; font-style: italic;"># game is over</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># add additional cards</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cards <span style="color: #66cc66;">=</span> numpy.<span style="color: black;">concatenate</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>cards<span style="color: #66cc66;">,</span> deck<span style="color: black;">&#91;</span>:<span style="color: #66cc66;">,</span> pos:pos + <span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> axis<span style="color: #66cc66;">=</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pos +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">3</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; nsolutions.<span style="color: black;">append</span><span style="color: black;">&#40;</span>nsets<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> nsolutions</div></td></tr></tbody></table></div>
</pre>
<p>The distribution of the number of sets on the table at any point in time looks quite different now (after simulating <del datetime="2010-09-21T14:40:52+00:00">1000</del> 5000 random games):</p>
<div id="attachment_389" class="wp-caption aligncenter" style="width: 410px"><img src="http://www.masterbaboon.com/wp-content/uploads/2010/09/histogram_game_draws1.png" alt="histogram_game_draws" title="histogram_game_draws" width="400" height="248" class="aligncenter size-full wp-image-453" /><p class="wp-caption-text">Probability of there being a given number of sets on the table at any point in a Set game.</p></div>
<p>As you see, the probability of there being no set on the table tripled and became about 1 in 10!  Now that's a relief, it is not that weird not to be able to find a set... or is it? The distribution also tells us that about half of the times there are <em>3 sets or more</em> on the table! Now that one, I didn't expect... (43 percent of the times, to be precise.)</p>
<p>The code and other material is available on the git repository at <a href="http://github.com/pberkes/masterbaboon/tree/master/projects/setgame/">http://github.com/pberkes/masterbaboon/tree/master/projects/setgame/</a> .</p>
<p><strong>Update 09/21/10:</strong> I updated the histogram of number of sets during a game with more games, so that the result is more accurate. The probability of not having a set at any point is even higher than reported before.</p>
<p><em>Cards and game © 1988, 1991 Cannei, LLC.  All rights reserved.  SET® is  registered trademark of Cannei, LLC.  Used with permission from Set  Enterprises, Inc.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.masterbaboon.com/2010/09/solving-the-game-set/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

