<?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>#AltDevBlogADay &#187; David Czarnecki</title>
	<atom:link href="http://www.altdevblogaday.com/author/david-czarnecki/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.altdevblogaday.com</link>
	<description>Each day a little more #gamedev love</description>
	<lastBuildDate>Mon, 20 May 2013 21:33:38 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Put On Your Game Face (revisited)</title>
		<link>http://www.altdevblogaday.com/2013/01/29/put-on-your-game-face-revisited/</link>
		<comments>http://www.altdevblogaday.com/2013/01/29/put-on-your-game-face-revisited/#comments</comments>
		<pubDate>Tue, 29 Jan 2013 04:25:58 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[General Interest]]></category>

		<guid isPermaLink="false">http://www.altdevblogaday.com/?p=29137</guid>
		<description><![CDATA[<p><span style="text-decoration: underline">TL;DR</span></p>
<p>About a year ago, <a href="http://www.altdevblogaday.com/2012/03/28/put-on-your-game-face/">I wrote a blog post</a> here about a weekly blog series on our company blog called <a href="http://blog.agoragames.com/blog/category/game-face/">&#8220;Game Face&#8221;</a>. A blog post revisiting a blog post about blog posts? It&#8217;s blog posts all the way down. As a refresher, &#8220;Game Face&#8221; is “our weekly round-up of our internal and external open source work at Agora Games. Internal open source refers to our public projects that you can find over at our <a href="https://github.com/agoragames/">Agora Games GitHub</a> account. External open source work refers to projects that we contribute to in off-hours and may or may not have anything to do with video games because we’re swell folks like that.” How&#8217;d we do in our open source efforts over the last year? Read on&#8230;</p>
<p><a href="http://www.altdevblogaday.com/2013/01/29/put-on-your-game-face-revisited/" class="more-link">Read more on Put On Your Game Face (revisited)&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><span style="text-decoration: underline">TL;DR</span></p>
<p>About a year ago, <a href="http://www.altdevblogaday.com/2012/03/28/put-on-your-game-face/">I wrote a blog post</a> here about a weekly blog series on our company blog called <a href="http://blog.agoragames.com/blog/category/game-face/">&#8220;Game Face&#8221;</a>. A blog post revisiting a blog post about blog posts? It&#8217;s blog posts all the way down. As a refresher, &#8220;Game Face&#8221; is “our weekly round-up of our internal and external open source work at Agora Games. Internal open source refers to our public projects that you can find over at our <a href="https://github.com/agoragames/">Agora Games GitHub</a> account. External open source work refers to projects that we contribute to in off-hours and may or may not have anything to do with video games because we’re swell folks like that.” How&#8217;d we do in our open source efforts over the last year? Read on&#8230;</p>
<p><span style="text-decoration: underline">THE BRASS TACKS</span></p>
<p>In 2011, <a href="http://blog.agoragames.com/blog/2012/01/09/2011-open-source-projects/">we open sourced 22 projects</a>. In 2012, <a href="http://blog.agoragames.com/blog/2012/12/14/game-face-41/">we open sourced 33 projects</a>. Obviously not all of these projects are going to &#8220;stick&#8221;, but one man&#8217;s trash is another man&#8217;s treasure right? The projects aren&#8217;t trash, BTW. A few projects came out of internal company-wide Hack-A-Thon sessions that we run every 2 months, but a fair number of them are taken from production applications. In looking at the 2012 project breakdown, by language, we have Ruby (22), Python (3), CoffeeScript (3), JavaScript (2), C++ (2), PHP (1). 7 of our engineers and 21 external people contributed to the various projects that we open sourced in 2012. Contributions range from clarifications in documentation to major new features that are developed, documented and tested.</p>
<p>It is very easy for us to track contributions to all of our open source projects. All of the projects are setup with a service hook to notify our company&#8217;s &#8220;Open Source&#8221; chat room when events happen like code is committed or a pull request is opened or an issue is filed. Every week I create a new &#8220;shell&#8221; for the &#8220;Game Face&#8221; blog post after the last one is published. I set it to be published automatically at 9 AM on the following Friday. As contributions come in to our open source projects, next week&#8217;s blog post is updated.</p>
<p>I&#8217;m not sure if we&#8217;ll open source more projects than we did in 2012. 33 is a fair number of projects to have open sourced. We obviously want quality over quantity. I&#8217;m always pushing to see if there&#8217;s anything we can open source. One of the ideas being tossed around as a way to expand our open source efforts would be to hold a weekly &#8220;Office Hours&#8221; session where a few engineers hop onto IRC or a Google &#8220;hangout&#8221; for an hour or so and field questions on our projects.</p>
<p><span style="text-decoration: underline">FIN</span></p>
<p>We are happy to contribute back in any way we can to open source software, whether it be our own projects or the projects we use on a daily basis. Again, if your company does anything with open source, I’d love to know about it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2013/01/29/put-on-your-game-face-revisited/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Costco-ification of Leaderboards</title>
		<link>http://www.altdevblogaday.com/2012/06/09/the-costco-ification-of-leaderboards/</link>
		<comments>http://www.altdevblogaday.com/2012/06/09/the-costco-ification-of-leaderboards/#comments</comments>
		<pubDate>Sat, 09 Jun 2012 03:44:01 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[bulk operations]]></category>
		<category><![CDATA[costco]]></category>
		<category><![CDATA[leaderboard]]></category>
		<category><![CDATA[redis]]></category>

		<guid isPermaLink="false">http://www.altdevblogaday.com/?p=26545</guid>
		<description><![CDATA[<p><span style="text-decoration: underline"><strong>TL;DR</strong></span></p>
<p>It&#8217;s beneficial, sometimes, to buy in bulk. Or in this case, to rank in bulk. I&#8217;ll take a look at a recent improvement to our open source <a href="https://github.com/agoragames/leaderboard">leaderboard</a> library to show significant improvement when doing a bulk insert operation for ranking members in a leaderboard.</p>
<p><a href="http://www.altdevblogaday.com/2012/06/09/the-costco-ification-of-leaderboards/" class="more-link">Read more on The Costco-ification of Leaderboards&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><span style="text-decoration: underline"><strong>TL;DR</strong></span></p>
<p>It&#8217;s beneficial, sometimes, to buy in bulk. Or in this case, to rank in bulk. I&#8217;ll take a look at a recent improvement to our open source <a href="https://github.com/agoragames/leaderboard">leaderboard</a> library to show significant improvement when doing a bulk insert operation for ranking members in a leaderboard.</p>
<p><span id="more-26545"></span></p>
<p><span style="text-decoration: underline"><strong>COSTCO AND YOU</strong></span></p>
<p>Let&#8217;s face it, we&#8217;ve all been walking through Costco or Sam&#8217;s Club at one point and we&#8217;ve thought to ourselves, &#8220;I do need a palette of chocolate covered pretzels.&#8221; or &#8220;We could use a drum of grape jam at home.&#8221; Regardless of whether or not these are valid units of measurement, the time it takes to purchase an item in bulk is less than the time it takes to purchase the items individually when you know you&#8217;re going to need the bulk amount. So let&#8217;s explore this idea with leaderboards.</p>
<p>Let&#8217;s look at the performance of ranking 1 million members in a leaderboard.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="ruby" style="font-family:monospace;">insert_time = <span style="color:#CC00FF; font-weight:bold;">Benchmark</span>.<span style="color:#9900CC;">measure</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  <span style="color:#006666;">1</span>.<span style="color:#9900CC;">upto</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1000000</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>index<span style="color:#006600; font-weight:bold;">|</span>
    highscore_lb.<span style="color:#9900CC;">rank_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;member_#{index}&quot;</span>, index<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">29.340000</span> <span style="color:#006666;">15.050000</span> <span style="color:#006666;">44.390000</span> <span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">81.673507</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></td></tr></table></div>

<p>81 seconds isn&#8217;t bad, but can we do better? What if a catastrophic failure forces us to rebuild our leaderboards from scratch? Every second counts right? Let&#8217;s rank the same 1 million members in the leaderboard all at once.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="ruby" style="font-family:monospace;">member_data = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
 <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
<span style="color:#006666;">1</span>.<span style="color:#9900CC;">upto</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1000000</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>index<span style="color:#006600; font-weight:bold;">|</span>
  member_data <span style="color:#006600; font-weight:bold;">&lt;&lt;</span> <span style="color:#996600;">&quot;member_#{index}&quot;</span>
  member_data <span style="color:#006600; font-weight:bold;">&lt;&lt;</span> index
<span style="color:#9966CC; font-weight:bold;">end</span>
 <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">1</span>
insert_time = <span style="color:#CC00FF; font-weight:bold;">Benchmark</span>.<span style="color:#9900CC;">measure</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  highscore_lb.<span style="color:#9900CC;">rank_members</span><span style="color:#006600; font-weight:bold;">&#40;</span>member_data<span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
 <span style="color:#006600; font-weight:bold;">=&gt;</span>  <span style="color:#006666;">22.390000</span>   <span style="color:#006666;">6.380000</span>  <span style="color:#006666;">28.770000</span> <span style="color:#006600; font-weight:bold;">&#40;</span> <span style="color:#006666;">31.144027</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></td></tr></table></div>

<p>31 seconds! As it turns out, &#8220;buying in bulk&#8221; really paid off. It helps to understand your underlying data store, in this case <a href="http://redis.io/">Redis</a>, to know when it can handle bulk operations to your advantage. If we were to compare the time it&#8217;d take to rank, say 10 million members in a leaderboard, we&#8217;d be looking at almost 14 minutes (ranking individually) vs. 5 minutes (ranking in bulk).</p>
<p><span style="text-decoration: underline"><strong>FIN</strong></span></p>
<p>As shown in this post, bulk operations can significantly impact the performance of your systems if the underlying data store can optimize those bulk operations. So don&#8217;t worry about that <a href="http://www.youtube.com/watch?v=Qn_TAkPWJcU">desk of Cheez-Its</a> you just purchased. You&#8217;re worth it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2012/06/09/the-costco-ification-of-leaderboards/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Put On Your Game Face</title>
		<link>http://www.altdevblogaday.com/2012/03/28/put-on-your-game-face/</link>
		<comments>http://www.altdevblogaday.com/2012/03/28/put-on-your-game-face/#comments</comments>
		<pubDate>Wed, 28 Mar 2012 18:34:21 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[General Interest]]></category>
		<category><![CDATA[open source]]></category>

		<guid isPermaLink="false">http://altdevblogaday.com/?p=25233</guid>
		<description><![CDATA[<p><span style="text-decoration: underline"><strong>TL;DR</strong></span></p>
<p>I recently started a weekly blog series on our company blog called <a href="http://blog.agoragames.com/blog/category/game-face/">&#8220;Game Face&#8221;</a>. It is &#8220;our weekly round-up of our internal and external open source work here at Agora Games. Internal open source refers to our public projects that you can find over at our <a href="https://github.com/agoragames/">Agora Games GitHub</a> account. External open source work refers to projects that we contribute to in off-hours and may or may not have anything to do with video games because we’re swell folks like that.&#8221; This is important for our company and I think it should be for your company.</p>
<p><a href="http://www.altdevblogaday.com/2012/03/28/put-on-your-game-face/" class="more-link">Read more on Put On Your Game Face&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><span style="text-decoration: underline"><strong>TL;DR</strong></span></p>
<p>I recently started a weekly blog series on our company blog called <a href="http://blog.agoragames.com/blog/category/game-face/">&#8220;Game Face&#8221;</a>. It is &#8220;our weekly round-up of our internal and external open source work here at Agora Games. Internal open source refers to our public projects that you can find over at our <a href="https://github.com/agoragames/">Agora Games GitHub</a> account. External open source work refers to projects that we contribute to in off-hours and may or may not have anything to do with video games because we’re swell folks like that.&#8221; This is important for our company and I think it should be for your company.</p>
<p><span style="text-decoration: underline"><strong>PUTTING ON THE GAME FACE<br />
</strong></span></p>
<p>At the beginning of 2012, I did an assessment of all the projects <a href="http://blog.agoragames.com/blog/2012/01/09/2011-open-source-projects/">we open sourced in 2011</a>. Late much? 22 projects wasn&#8217;t bad and I want to beat that number in 2012, but it got me thinking that this kind of information is timely and needs more regular attention. So, I started kicking around ideas for a blog series name. After a day, I settled on &#8220;Game Face&#8221;. &#8220;Game&#8221; obviously referred to the work we do in developing gaming-related libraries and middleware. &#8220;Face&#8221; would refer to the code-wise public face of the company and the developer(s) working on the individual libraries.</p>
<p><span style="text-decoration: underline">It will help you become a better writer</span>: If you&#8217;re a developer and you&#8217;re scared about writing a weekly blog series, you shouldn&#8217;t be. The focus of the blog is technical in nature, so you don&#8217;t need to spend a lot of time on exposition. If you&#8217;re good with your commit messages or keeping a CHANGELOG, the blog posts write themselves. For example, from an item in a recent blog post, &#8220;This releases addresses the first future idea from the README when the gem was released over a year ago to add a method allowing for bulk insert of data into a leaderboard.&#8221; Cut and paste for the most part my friends. The intrepid developer might even automate the creation of the initial blog post that can be wordsmithed by someone you deem more fluent in languages other than C++ :)</p>
<p><span style="text-decoration: underline">It will help you become a better developer</span>: We get feedback on our code each day from our co-workers. By opening up your code to the world, you get peer feedback beyond your immediate peanut gallery. You also get comments, questions and sometimes code where developers are using your code in new and interesting ways that you hadn&#8217;t thought of yet. Case-and-point: I recently integrated a patch to our leaderboard library with all the <a href="https://github.com/agoragames/leaderboard/pull/5">code and tests to allow for leaderboards in &#8220;reverse&#8221;</a> (lowest-to-highest) sorted order. I just hadn&#8217;t come across that use case in the games we&#8217;ve worked on where I needed a leaderboard appropriate for a racing game. But someone else did. And now our library is better off because of it. Beyond peer feedback, or any feedback, opening up your code and talking about it helps you to think about the ramifications of changes when there are developers other than you or your company using your code.</p>
<p><span style="text-decoration: underline">It will help you as a company</span>: By highlighting your company&#8217;s open source work, it may motivate your developers to want to take a stab at open source in the first place or to clean up a library for external publishing. You might also attract developers who put a high value on knowing their contributions will be recognized, whether they are internal or external, and that their contributions may see the light of day outside of your company&#8217;s hallowed halls. The last &#8220;Game Face&#8221; blog post I wrote highlighted a new library one of our developers had released that allowed you to parse Beersmith2 (beer brewing software) files in Ruby. I imagine many video game companies rely on open source to some degree, and so by publicly promoting your contributions to open source, it can also help you in the eyes of the open source community.</p>
<p><span style="text-decoration: underline">It will help you have awkward conversations</span>: I can&#8217;t tell you what to open source and what not to open source. You&#8217;ll have to talk as a team, as a company, and possibly with your lawyers to understand what you can and cannot open source. In 2011, there was only one instance where I went to our CEO to get a check on, &#8220;Can I open source this?&#8221; We walked around the block and our conversation went basically as follows:</p>
<p>Me: &#8220;I&#8217;d like to open source a leaderboard library. Given this is a core thing we do, is that OK?&#8221;</p>
<p>CEO: &#8220;So, someone else could do this before us using a similar method?&#8221;</p>
<p>Me: &#8220;Yes.&#8221;</p>
<p>CEO: &#8220;Ship it!&#8221;</p>
<p><span style="text-decoration: underline"><strong>FIN</strong></span></p>
<p>Hopefully I&#8217;ve made some compelling arguments that your company should highlight your internal and external open source development. Our weekly blog post series highlighting our internal and external open source work comes out on Friday and now I usually get one or two messages throughout the week in our group chat room asking, &#8220;What&#8217;s going in to Game Face this week?&#8221; It feels pretty good when I can say back, &#8220;Your face.&#8221; If your company does anything with open source, I&#8217;d love to know about it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2012/03/28/put-on-your-game-face/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What Makes You &#8220;Tick&#8221; #3?</title>
		<link>http://www.altdevblogaday.com/2012/01/28/what-makes-you-tick-3/</link>
		<comments>http://www.altdevblogaday.com/2012/01/28/what-makes-you-tick-3/#comments</comments>
		<pubDate>Sat, 28 Jan 2012 05:06:50 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[General Interest]]></category>
		<category><![CDATA[bioshock]]></category>
		<category><![CDATA[tick]]></category>

		<guid isPermaLink="false">http://altdevblogaday.com/?p=23512</guid>
		<description><![CDATA[<p>In my previous &#8220;What Makes You &#8216;Tick&#8217;&#8221; posts, I&#8217;ve written about <a href="http://altdevblogaday.com/2011/05/16/what-makes-you-tick/">&#8220;thinking&#8221; at the keyboard</a> and my <a href="http://altdevblogaday.com/2011/07/15/what-makes-you-tick-2/">audio OCD</a>, but what about playing video games? Do I have any quirks when playing video games? You bet I do!</p>
<p><a href="http://www.altdevblogaday.com/2012/01/28/what-makes-you-tick-3/" class="more-link">Read more on What Makes You &#8220;Tick&#8221; #3?&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p>In my previous &#8220;What Makes You &#8216;Tick&#8217;&#8221; posts, I&#8217;ve written about <a href="http://altdevblogaday.com/2011/05/16/what-makes-you-tick/">&#8220;thinking&#8221; at the keyboard</a> and my <a href="http://altdevblogaday.com/2011/07/15/what-makes-you-tick-2/">audio OCD</a>, but what about playing video games? Do I have any quirks when playing video games? You bet I do!</p>
<p>I&#8217;m just going to cut to the chase here and present my &#8220;notes&#8221; when playing BioShock. You can find the <a href="http://www.flickr.com/photos/davidczarnecki/1430008396/">original at its Flickr photo page</a>.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2012/01/1430008396_5296c07060_z.jpg"><img class="alignnone size-full wp-image-23515" src="http://altdevblogaday.com/wp-content/uploads/2012/01/1430008396_5296c07060_z.jpg" alt="" width="495" height="640" /></a></p>
<div>
<p>&#8220;I took meticulous (bordering on insanity) notes during BioShock. This is the final sheet and I got to the point where each save was described by a set of acronyms as to what transpired since the last save.</p>
<p>GMS = Got more stuff<br />
HS = Hacked safe<br />
DBD! = Defeated Big Daddy<br />
HVM = Hacked vending machine<br />
KS = Killed splicers (when I was in an area where I had killed quite a few)<br />
GG = Gatherer&#8217;s Garden<br />
BHVM = Before hacking vending machine (I was low on auto hack tools)<br />
BMS = Bought more stuff<br />
HT = Hacked turret&#8221;</p>
<p>There were 7 other pages (front and back) of save game notes like above. I&#8217;ll be in Gamers Anonymous meetings for awhile ;)</p>
<p>Do you have any quirks when playing video games? What makes YOU &#8220;tick&#8221;? You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">@CzarneckiD</a>.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2012/01/28/what-makes-you-tick-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Waiting Game</title>
		<link>http://www.altdevblogaday.com/2012/01/11/the-waiting-game/</link>
		<comments>http://www.altdevblogaday.com/2012/01/11/the-waiting-game/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 03:38:49 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[General Interest]]></category>
		<category><![CDATA[loading time]]></category>
		<category><![CDATA[player perspective]]></category>
		<category><![CDATA[time experiment]]></category>
		<category><![CDATA[time management]]></category>
		<category><![CDATA[time perspective]]></category>
		<category><![CDATA[video games]]></category>
		<category><![CDATA[Xbox 360]]></category>

		<guid isPermaLink="false">http://altdevblogaday.com/?p=22661</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>I hate waiting for video games to load. Now I hate waiting for video games to load a little less. Why? I did some &#8220;science&#8221; to figure how just how long it takes for me to go from the point of clicking the button to select &#8220;Play&#8221; to where I&#8217;m actually playing the game. As it turns out, I just need to relax a little because I&#8217;m not actually spending a lot of time waiting for video games to load. I present the &#8220;Time To Play&#8221; numbers for 40 out of the 117 games I own on XBOX 360.</p>
<p><a href="http://www.altdevblogaday.com/2012/01/11/the-waiting-game/" class="more-link">Read more on The Waiting Game&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>I hate waiting for video games to load. Now I hate waiting for video games to load a little less. Why? I did some &#8220;science&#8221; to figure how just how long it takes for me to go from the point of clicking the button to select &#8220;Play&#8221; to where I&#8217;m actually playing the game. As it turns out, I just need to relax a little because I&#8217;m not actually spending a lot of time waiting for video games to load. I present the &#8220;Time To Play&#8221; numbers for 40 out of the 117 games I own on XBOX 360.</p>
<p><strong>Time To Play (TTP)<br />
</strong></p>
<p>The experimental &#8220;setup&#8221; was as follows:</p>
<ol>
<li>Insert game disc into XBOX 360</li>
<li>Start the stopwatch on my phone when I click the &#8220;Play&#8221; square in the XBOX dashboard</li>
<li>Try to click through the loading screens and menus as quick as possible to get to a single-player (SP) or multi-player (MP) game</li>
<li>Stop the stopwatch on my phone at the point where the SP or MP game was loaded and I was playing</li>
</ol>
<p>Notes:</p>
<ul>
<li>I do not have any games loaded onto my hard drive</li>
<li>I was connected to XBOX Live the entire time</li>
<li>If there was a title update for the game, I restarted from Step 1</li>
<li>If I didn&#8217;t have a TTP number for SP or MP, it&#8217;s because I typically don&#8217;t play the game in that mode or that mode is not offered in the particular title</li>
<li>TTP numbers are in minutes and seconds</li>
</ul>
<p>These are the &#8220;Time To Play&#8221; numbers for 40 out of the 117 XBOX 360 games that I own.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2012/01/Screen-Shot-2012-01-10-at-10.05.20-PM.png"><img class="alignnone size-full wp-image-22666" src="http://altdevblogaday.com/wp-content/uploads/2012/01/Screen-Shot-2012-01-10-at-10.05.20-PM.png" alt="" width="638" height="728" /></a></p>
<p>If you would like to download the PDF of the spreadsheet, you can download it at <a href="http://altdevblogaday.com/wp-content/uploads/2012/01/XBOX-360-Time-To-Play.pdf">XBOX 360 Time To Play</a>.</p>
<p><strong>Numb3rs</strong></p>
<p><strong></strong>As it turns out, I&#8217;m only spending a little over a minute from the time I want to play a game to the time I am actually playing that game. Call of Duty: Modern Warfare 2 and Call of Duty: Modern Warfare 3 had the best TTP for both SP and MP games clocking in at just under a minute. I&#8217;m honestly not sure what was going on with Halo: Reach SP loading as it had the slowest TTP of 3:31.2.</p>
<p>I&#8217;m still going to be clicking through the menus to play games as quick as possible, save for that first time through where I don&#8217;t have a save game, but I&#8217;ll be doing so with a more tempered head.</p>
<p><strong>The Real Travesty</strong></p>
<p>Psychonauts was an &#8220;Unrecognized Disc&#8221;. I died a little inside. I think it might be due to the fact that Microsoft sent me a new XBOX 360 after my freezing issues with Halo: Reach and the latest drive doesn&#8217;t recognize the original XBOX discs.</p>
<p>Thanks for reading. You can find more hilarity over on my Twitter account, <a href="https://twitter.com/#%21/czarneckid">@CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2012/01/11/the-waiting-game/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Leaderboard Benchmarking</title>
		<link>http://www.altdevblogaday.com/2011/12/31/leaderboard-benchmarking/</link>
		<comments>http://www.altdevblogaday.com/2011/12/31/leaderboard-benchmarking/#comments</comments>
		<pubDate>Sat, 31 Dec 2011 21:46:48 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[leaderboard]]></category>
		<category><![CDATA[redis]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://altdevblogaday.com/?p=22282</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>I recently got a new MacBook Pro and I wanted to do some benchmarking. Naturally I turned to the <a href="https://github.com/agoragames/leaderboard">leaderboard</a> library I maintain which already had a base set of benchmarks that I could compare the results to on my new computer. You may also recall I&#8217;ve written about leaderboards before <a href="http://altdevblogaday.com/?s=leaderboard+czarnecki">here</a> on #AltDevBlogADay. In this blog post I&#8217;ll discuss two &#8220;knobs&#8221; I tweaked to get more performance out of the leaderboard library, the underlying interpreter and an underlying client library. While there was definitely a speed improvement when switching the underlying interpreter to a more recent version, there was a more significant speed improvement when switching the underlying client library.</p>
<p><a href="http://www.altdevblogaday.com/2011/12/31/leaderboard-benchmarking/" class="more-link">Read more on Leaderboard Benchmarking&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>I recently got a new MacBook Pro and I wanted to do some benchmarking. Naturally I turned to the <a href="https://github.com/agoragames/leaderboard">leaderboard</a> library I maintain which already had a base set of benchmarks that I could compare the results to on my new computer. You may also recall I&#8217;ve written about leaderboards before <a href="http://altdevblogaday.com/?s=leaderboard+czarnecki">here</a> on #AltDevBlogADay. In this blog post I&#8217;ll discuss two &#8220;knobs&#8221; I tweaked to get more performance out of the leaderboard library, the underlying interpreter and an underlying client library. While there was definitely a speed improvement when switching the underlying interpreter to a more recent version, there was a more significant speed improvement when switching the underlying client library.</p>
<p><span id="more-22282"></span></p>
<p><strong>TWEAKING KNOBS</strong></p>
<p>The benchmarks were run on a 2.5 GHz Intel Core i7 MacBook Pro with 8 GB of memory under OS X Lion 10.7.2 using Redis 2.4.5. They measured the total amount of time to rank 10 million people in a leaderboard using sequential scores, total amount of time to rank 10 million people in a leaderboard using random scores and the average time to retrieve an arbitrary page from the leaderboard. The basic benchmarking code can be found in the README on the <a href="https://github.com/agoragames/leaderboard">leaderboard</a> project page.</p>
<p><span style="text-decoration: underline">Switching Ruby Interpreters</span></p>
<p>Below are the benchmark results from switching between different Ruby interpreters, Ruby 1.8.7, Ruby 1.9.2 and Ruby 1.9.3. Values are in seconds.</p>
<p><span style="text-decoration: underline">Ruby 1.8.7</span></p>
<p style="padding-left: 30px">Time to rank 10 million people in a leaderboard (sequential scores): 794.157420158386</p>
<p style="padding-left: 30px">Time to rank 10 million people in a leaderboard (random scores): 849.301838159561</p>
<p style="padding-left: 30px">Average time to retrieve an arbitrary page from the leaderboard (50,000 requests): 0.00165219999999999</p>
<p><span style="text-decoration: underline">Ruby 1.9.2</span></p>
<p style="padding-left: 30px">Time to rank 10 million people in a leaderboard (sequential scores): 656.387526</p>
<p style="padding-left: 30px">Time to rank 10 million people in a leaderboard (random scores): 748.955826</p>
<p style="padding-left: 30px">Average time to retrieve an arbitrary page from the leaderboard (50,000 requests): 0.0011321999999999895</p>
<p><span style="text-decoration: underline">Ruby 1.9.3</span></p>
<p style="padding-left: 30px">Time to rank 10 million people in a leaderboard (sequential scores): 651.057383</p>
<p style="padding-left: 30px">Time to rank 10 million people in a leaderboard (random scores): 719.157958</p>
<p style="padding-left: 30px">Average time to retrieve an arbitrary page from the leaderboard (50,000 requests): 0.001079199999999996</p>
<p><span style="text-decoration: underline">Summary</span></p>
<p style="padding-left: 30px">Ruby 1.8.7 to Ruby 1.9.3 (sequential scores): 18% improvement</p>
<p style="padding-left: 30px">Ruby 1.8.7 to Ruby 1.9.3 (random scores): 15% improvement</p>
<p style="padding-left: 30px">Ruby 1.8.7 to Ruby 1.9.3 (average page request): 34% improvement</p>
<p><span style="text-decoration: underline">Switching Redis Client Library</span></p>
<p>I decided not to benchmark Ruby 1.8.7 or Ruby 1.9.2 in tweaking the client driver &#8220;knob&#8221;.</p>
<p>Below are the benchmark results using Ruby 1.9.3 with the <a href="https://github.com/antirez/hiredis">hiredis-rb</a> client library. Values are in seconds.</p>
<p><span style="text-decoration: underline">Ruby 1.9.3 and hiredis</span></p>
<p style="padding-left: 30px">Time to rank 10 million people in a leaderboard (sequential scores): 472.544572</p>
<p style="padding-left: 30px">Time to rank 10 million people in a leaderboard (random scores): 549.911350</p>
<p style="padding-left: 30px">Average time to retrieve an arbitrary page from the leaderboard (50,000 requests): 0.0003803999999999928</p>
<p><span style="text-decoration: underline">Summary</span></p>
<p style="padding-left: 30px">Ruby 1.8.7 to Ruby 1.9.3/hiredis (sequential scores): 40% improvement</p>
<p style="padding-left: 30px">Ruby 1.8.7 to Ruby 1.9.3/hiredis (random scores): 35% improvement</p>
<p style="padding-left: 30px">Ruby 1.8.7 to Ruby 1.9.3/hiredis (average page request): 76% improvement</p>
<p style="padding-left: 30px">Ruby 1.9.3 to Ruby 1.9.3/hiredis (sequential scores): 27% improvement</p>
<p style="padding-left: 30px">Ruby 1.9.3 to Ruby 1.9.3/hiredis (random scores): 23% improvement</p>
<p style="padding-left: 30px">Ruby 1.9.3 to Ruby 1.9.3/hiredis (average page request): 64% improvement</p>
<p><strong>WRAPUP</strong></p>
<p>It seems every aspect of video game technology is tweaked to maximize performance, whether it be frames per second or requests per second. Fiddling with very basic &#8220;knobs&#8221; here, I was able to get decent improvements in writing to and reading from a leaderboard of non-trivial size. Further speed improvements could potentially be realized by using a socket-based connection versus a TCP-based connection as well as faster hardware optimized for a server environment versus an off-the-shelf laptop.</p>
<p>Thanks for indulging my leaderboard nerdery yet again. You can find more hilarity over on my Twitter account, <a href="https://twitter.com/#!/czarneckid">@CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/12/31/leaderboard-benchmarking/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Leaderboard Hack-A-Thon Post-mortem</title>
		<link>http://www.altdevblogaday.com/2011/08/30/leaderboard-hack-a-thon-post-mortem/</link>
		<comments>http://www.altdevblogaday.com/2011/08/30/leaderboard-hack-a-thon-post-mortem/#comments</comments>
		<pubDate>Tue, 30 Aug 2011 02:33:49 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[erlang]]></category>
		<category><![CDATA[hack-a-thon]]></category>
		<category><![CDATA[hackathon]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[leaderboard]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[scala]]></category>

		<guid isPermaLink="false">http://altdevblogaday.com/?p=15238</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>In my last post about our internal studio <a href="http://altdevblogaday.com/2011/07/30/hack-a-thon/">Hack-A-Thon</a>, I concluded with:</p>
<blockquote><p>At our upcoming Hack-A-Thon, I’m going to be working on rewriting the internals of our open source <a href="https://github.com/agoragames/leaderboard">leaderboard</a> code. More specifically, I want to change the API to be more readable and self documenting as well as to take advantage of transactions to get consistent snapshots of leaderboard data. After that I’m going to re-run the performance metrics to see how transactions affects the leaderboard data retrieval. Next up will be updating the public documentation. Finally I’ll release a new library of the leaderboard code. And then I’m going to do all of that for the PHP, Java, and Scala ports. That’s the plan at least.</p></blockquote>
<p>What was it they say about the best laid schemes of mice and men?</p>
<p><a href="http://www.altdevblogaday.com/2011/08/30/leaderboard-hack-a-thon-post-mortem/" class="more-link">Read more on Leaderboard Hack-A-Thon Post-mortem&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>In my last post about our internal studio <a href="http://altdevblogaday.com/2011/07/30/hack-a-thon/">Hack-A-Thon</a>, I concluded with:</p>
<blockquote><p>At our upcoming Hack-A-Thon, I’m going to be working on rewriting the internals of our open source <a href="https://github.com/agoragames/leaderboard">leaderboard</a> code. More specifically, I want to change the API to be more readable and self documenting as well as to take advantage of transactions to get consistent snapshots of leaderboard data. After that I’m going to re-run the performance metrics to see how transactions affects the leaderboard data retrieval. Next up will be updating the public documentation. Finally I’ll release a new library of the leaderboard code. And then I’m going to do all of that for the PHP, Java, and Scala ports. That’s the plan at least.</p></blockquote>
<p>What was it they say about the best laid schemes of mice and men?</p>
<p><span id="more-15238"></span></p>
<p><strong>AWRY WE GO</strong></p>
<p>I started working with the <a href="https://github.com/agoragames/leaderboard">leaderboard</a> code in Ruby at 4 PM on the day of the Hack-A-Thon. As stated above, I wanted to change the API to be more readable and self documenting as well as to take advantage of transactions to get consistent snapshots of leaderboard data. This was particularly important because leaderboards are constantly being updated and re-ranked in real-time and without transactions, the data returned to the client could have changed, resulting in stale/inaccurate data. After that I re-ran the performance metrics to see how transactions affected the leaderboard data retrieval. The good news is that transactions didn&#8217;t affect leaderboard data retrieval. At least in the planned usage scenario where you&#8217;d be pulling data from a leaderboard read slave. I do want to get concurrent read/write performance metrics as well. How about that for a follow-up blog post? I digress. Next up was updating the public documentation. Finally I released a new library with the updated leaderboard code. I actually waited a few weeks to do this, although there was no specific reason I didn&#8217;t cut a new library package at the end of the Hack-A-Thon. All of the initial leaderboard development work took me through 11 PM, with a couple of hours of non-working in-between to go to the gym, grab dinner at home, shower, and back to the studio. My trusty <a href="http://twitpic.com/610jmp">&#8220;companion cube&#8221;</a> was with me as well. I had a game plan based on my revision history to the leaderboard code to tackle the rewrite in the next language, Scala.</p>
<p>The <a href="https://github.com/agoragames/scala-leaderboard">scala-leaderboard</a> API, documentation and performance metric updates obviously went quicker. I finished those updates around 4:30 AM. 12 hours into the Hack-A-Thon, being up for nearly 24 hours at this point and I was still going strong. Let&#8217;s randomly pick another language, PHP.</p>
<p>That&#8217;s right folks, I decided to tackle the updates to the <a href="https://github.com/agoragames/php-leaderboard">PHP leaderboard</a> library. At 5 AM. We&#8217;re partying now, right? <a href="http://www.youtube.com/watch?v=oWUgTNYK7Tk">Speaking of dick killing parties</a> (watch that video for one of the best ROFLMAO scenes from Bulletstorm). So yeah, the next time someone invites you to a PHP party at 5 AM, you know what kind of party it is. I digress. I basically got sucked into a vortex of hellfire and doom trying to get the PHP environment I somehow had set up on my home machine on my work machine. I worked at it for an hour or so. <a href="http://twitpic.com/6177y8">I greeted the sunrise</a>. And then I took a 40 minute nap. Around 7:30 AM, people were starting to filter into the studio and a bunch of us decided to go for breakfast. I just needed a recharge. After breakfast I worked at the PHP environment for another couple of hours, flipped my desk over (not really), and rallied for the final push of leaderboard updates in the final language, Java.</p>
<p>I got through the API updates to the <a href="https://github.com/agoragames/java-leaderboard">Java leaderboard</a> library. I still have yet to finish off the documentation and performance metric updates.</p>
<p><strong>FIN</strong></p>
<p>All-in-all, the Hack-A-Thon was a success.</p>
<p>During the Hack-A-Thon, another colleague did his own port of the leaderboard library and so we have a good start on the <a href="https://github.com/agoragames/erlang-leaderboard">erlang leaderboard</a> library. Recently another colleague did a port of the leaderboard library to NodeJS and so we have the <a href="https://github.com/omork/node-leaderboard">node leaderboard</a> library.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/08/30/leaderboard-hack-a-thon-post-mortem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hack-A-Thon</title>
		<link>http://www.altdevblogaday.com/2011/07/30/hack-a-thon/</link>
		<comments>http://www.altdevblogaday.com/2011/07/30/hack-a-thon/#comments</comments>
		<pubDate>Sat, 30 Jul 2011 23:16:56 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[General Interest]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[hack-a-thon]]></category>
		<category><![CDATA[hackathon]]></category>

		<guid isPermaLink="false">http://altdevblogaday.com/?p=12952</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>In a week, we&#8217;re running an internal Hack-A-Thon at the studio. It&#8217;ll be the third one we&#8217;ve run. For 24 hours, everyone in the company participates and can work on whatever project they&#8217;d like to work on as long it&#8217;s somewhat (for a very relaxed definition of somewhat) related to the work that we do. It&#8217;s a great time.</p>
<p><a href="http://www.altdevblogaday.com/2011/07/30/hack-a-thon/" class="more-link">Read more on Hack-A-Thon&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>In a week, we&#8217;re running an internal Hack-A-Thon at the studio. It&#8217;ll be the third one we&#8217;ve run. For 24 hours, everyone in the company participates and can work on whatever project they&#8217;d like to work on as long it&#8217;s somewhat (for a very relaxed definition of somewhat) related to the work that we do. It&#8217;s a great time.</p>
<p><span id="more-12952"></span><strong>HACKITY HACK HACK A ROO</strong></p>
<p>Officially the Hack-A-Thon starts at 3 PM on a Thursday and finishes at 3 PM on Friday. Past Hack-A-Thon projects have included:</p>
<p>- Migrating the software on our continuous integration server</p>
<p>- iPhone application for interfacing to our platform services</p>
<p>- Unity video game where the studio was modeled and the game could be used as a testbed for sending game data to our platform services</p>
<p>- Video conferencing setup</p>
<p>- Internal project theme song, rap and artwork</p>
<p>- Open source testing framework</p>
<p>Before past Hack-A-Thons, I&#8217;ve gone home, hit the gym, grabbed dinner, showered and tried to nap. I&#8217;ve always been the first one to start before midnight and then it&#8217;s straight on &#8217;till morning. Usually I can make it until around 7 AM when I have to take a 20 min nap, followed by breakfast, and then it&#8217;s back to coding until the wrap session.</p>
<p>Here&#8217;s some tips for making sure your Hack-A-Thon is successful:</p>
<p>1. Be inclusive &#8211; Everyone in the organization should participate. Encourage teams to be formed well in advance of the Hack-A-Thon. Let production work with development. Let development work with HR. However people want to form teams or work solo, let it happen.</p>
<p>2. Be open &#8211; No secret projects. Make sure everyone&#8217;s ideas are known ahead of the Hack-A-Thon. Even if someone wants to work on their project alone, it&#8217;s more exciting for everyone when they know someone might be rewriting a core piece of your game engine or simply getting video conferencing working flawlessly in your conference room. If you can involve the local development community, do that too. You never know the talent you might be able to attract by opening your doors for a day.</p>
<p>3. Be free &#8211; Be very lax in what people are allowed to work on. Projects should be somehow related to the work you&#8217;re doing, but they don&#8217;t need to be production-ready at the end of the Hack-A-Thon. Let people explore.</p>
<p>4. Be mindful &#8211; It&#8217;s the game industry. There are milestones. There are launches. There are conferences. Make sure you plan your Hack-A-Thon on a day that doesn&#8217;t preclude half your staff from participating because of a conflict.</p>
<p>5. Be focused &#8211; Shut down the tab to GMail or don&#8217;t open Outlook. Encourage teams to talk in person. Try and be as focused and productive as you can be in the allotted time. Unless absolutely necessary, e.g. our data center servers are actually on fire, focus on your Hack-A-Thon project and not your regular work.</p>
<p>6. Be scoped &#8211; Try and choose a Hack-A-Thon project you can actually scope to the allotted time. It&#8217;s more fun when you can demonstrate a near complete project at the end of your Hack-A-Thon.</p>
<p>7. Be closing &#8211; Provide a wrap-up session where people get 5 minutes or so at the end of the Hack-A-Thon to demo their project to everyone. And clap at the end of each demo. Even if people don&#8217;t complete 100% of what they wanted to get done, applaud the effort.</p>
<p>8. Be publicizing &#8211; Talk about the Hack-A-Thon on your company&#8217;s Twitter, Facebook or blog. Hint at some awesome upcoming projects that are spawned from the Hack-A-Thon or link to open source projects.</p>
<p><strong>FIN</strong></p>
<p>At our upcoming Hack-A-Thon, I&#8217;m going to be working on rewriting the internals of our open source <a href="https://github.com/agoragames/leaderboard">leaderboard</a> code. More specifically, I want to change the API to be more readable and self documenting as well as to take advantage of transactions to get consistent snapshots of leaderboard data. After that I&#8217;m going to re-run the performance metrics to see how transactions affects the leaderboard data retrieval. Next up will be updating the public documentation. Finally I&#8217;ll release a new library of the leaderboard code. And then I&#8217;m going to do all of that for the PHP, Java, and Scala ports. That&#8217;s the plan at least.</p>
<p>24 hours of coding.</p>
<p>\m/ \m/</p>
<p>You can find more hilarity over on my Twitter account,  <a href="http://twitter.com/czarneckid">@CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/07/30/hack-a-thon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What Makes You &#8220;Tick&#8221; #2?</title>
		<link>http://www.altdevblogaday.com/2011/07/15/what-makes-you-tick-2/</link>
		<comments>http://www.altdevblogaday.com/2011/07/15/what-makes-you-tick-2/#comments</comments>
		<pubDate>Fri, 15 Jul 2011 02:00:01 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[General Interest]]></category>
		<category><![CDATA[foo fighters]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[ocd]]></category>
		<category><![CDATA[rockabye baby]]></category>
		<category><![CDATA[silversun pickups]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[zz top]]></category>

		<guid isPermaLink="false">http://altdevblogaday.com/?p=11524</guid>
		<description><![CDATA[<p>I&#8217;m going to keep this #AltDevBlogADay post short. In <a href="http://altdevblogaday.com/2011/05/16/what-makes-you-tick/">my last &#8220;What Makes You Tick?&#8221;</a> post, I talked about my personal &#8220;tick&#8221; when thinking at the keyboard. I also have an audio &#8220;tick&#8221;. Well, maybe not so much a &#8220;tick&#8221; as audio OCD. As I&#8217;m sure a lot of you do too, I love listening to music while coding. However, there are some days when I listen to a single song on repeat for the entire day. Today it was Foo Fighters &#8211; The Pretender. About a week ago it was Silversun Pickups &#8211; Panic Switch. And before that I can remember it was ZZ Top &#8211; Cheap Sunglasses. There&#8217;s absolutely no rhyme or reason to the song selection. And more often than not, I&#8217;m listening to multiple albums throughout the day. But, to be honest, there are those days when a song gets me into a groove and it&#8217;s &#8220;lather, rinse, repeat&#8221; the entire day.</p>
<p><a href="http://www.altdevblogaday.com/2011/07/15/what-makes-you-tick-2/" class="more-link">Read more on What Makes You &#8220;Tick&#8221; #2?&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m going to keep this #AltDevBlogADay post short. In <a href="http://altdevblogaday.com/2011/05/16/what-makes-you-tick/">my last &#8220;What Makes You Tick?&#8221;</a> post, I talked about my personal &#8220;tick&#8221; when thinking at the keyboard. I also have an audio &#8220;tick&#8221;. Well, maybe not so much a &#8220;tick&#8221; as audio OCD. As I&#8217;m sure a lot of you do too, I love listening to music while coding. However, there are some days when I listen to a single song on repeat for the entire day. Today it was Foo Fighters &#8211; The Pretender. About a week ago it was Silversun Pickups &#8211; Panic Switch. And before that I can remember it was ZZ Top &#8211; Cheap Sunglasses. There&#8217;s absolutely no rhyme or reason to the song selection. And more often than not, I&#8217;m listening to multiple albums throughout the day. But, to be honest, there are those days when a song gets me into a groove and it&#8217;s &#8220;lather, rinse, repeat&#8221; the entire day.</p>
<p>I&#8217;ve also found that I prefer to ease into my day musically. I can&#8217;t just go for the gusto with Slayer &#8211; Raining Blood. It&#8217;s too much of a shock for my system. Most days I start off with one of the <a href="http://rockabyebabymusic.com/">Rockabye Baby</a> albums. In case you don&#8217;t know, they&#8217;re lullaby renditions of popular songs from artists ranging from AC/DC to The Cure to Tool. All of the albums are fantastic. I&#8217;ve found that it helps me to mentally prepare for the unexpected. For example, <a href="http://www.youtube.com/watch?v=hglVqACd1C8">Tool &#8211; Sober</a>, and <a href="http://www.rockabyebabymusic.com/ecom2/index.php/music/rockabye-baby-lullaby-renditions-of-tool.html">Tool &#8211; Sober</a> (snippet of the lullaby rendition). Expected in one case. Unexpected in the other case. Awesome sauce in both cases.</p>
<p>What makes you &#8220;tick&#8221; &#8230; musically?</p>
<p>You can find more hilarity over on my Twitter account,  <a href="http://twitter.com/czarneckid">@CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/07/15/what-makes-you-tick-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Re-Education (Through Leaderboards)</title>
		<link>http://www.altdevblogaday.com/2011/06/30/re-education-through-leaderboards/</link>
		<comments>http://www.altdevblogaday.com/2011/06/30/re-education-through-leaderboards/#comments</comments>
		<pubDate>Thu, 30 Jun 2011 11:54:54 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[go]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[leaderboard]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://altdevblogaday.com/?p=9996</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>In the last 2 weeks I&#8217;ve ported my <a href="https://github.com/agoragames/leaderboard">leaderboard</a> library, originally written in Ruby, to PHP and Java. It has been an extremely fulfilling endeavor for a number of reasons.</p>
<p><a href="http://www.altdevblogaday.com/2011/06/30/re-education-through-leaderboards/" class="more-link">Read more on Re-Education (Through Leaderboards)&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>In the last 2 weeks I&#8217;ve ported my <a href="https://github.com/agoragames/leaderboard">leaderboard</a> library, originally written in Ruby, to PHP and Java. It has been an extremely fulfilling endeavor for a number of reasons.</p>
<p><span id="more-9996"></span><img src="http://blog.agoragames.com/wp-includes/js/tinymce/plugins/wordpress/img/trans.gif" alt="" /></p>
<p><strong>99 PROBLEMS<br />
</strong></p>
<p>Let&#8217;s face it, we&#8217;ve all been on epic e-mail threads where someone  poses a problem, e-mail armchair development ensues and people argue  back and forth about what will and what not work, and at the end of the  thread, the original author is left with more questions than answers,  more what could be than what should be. That happened to me about two  weeks ago. It all started with a Friday evening e-mail to engineering, &#8220;We have a vexing leaderboard issue I&#8217;m  opening up for suggestions.&#8221; It was for a property we didn&#8217;t write, but  one that was in dire need of help. The thread was 20 e-mails in before I  responded at 9 AM the next day with (paraphrasing here): &#8220;I made this for you. Use it or  don&#8217;t. At the very least, it can be tested right now as a potential  solution.&#8221;</p>
<p>And so the <a href="https://github.com/agoragames/php-leaderboard">php-leaderboard</a> library was born. I had unleashed PHP unto this world. But, it was  fully tested. And I also went through the steps to ensure that other  developers could find it via the <a href="http://pearhub.org/">PearHub</a> package system (<a href="http://pearhub.org/projects/php_leaderboard">php_leaderboard package</a>).</p>
<p>If it had turned out, given the constraints, that php-leaderboard  wasn&#8217;t going to be a viable solution, it really wasn&#8217;t going to phase  me. I learned some PHP. I was like Jojo the idiot circus boy with a  pretty new pet. Now the pet is my possible solution. <em>&#8220;</em>Oh, my   pretty little pet, I love you. And then I stroke it, and I pet it, and I   massage it. Hehe, I love it, I love my little naughty pet, you&#8217;re   naughty! And then I take my naughty pet and I go &#8230;&#8221; Wait &#8230; <a href="http://www.youtube.com/watch?v=jCyaXh-VZco">what</a>?  The point is I found some inspiration to try something new and to  present a reasonably complete solution to the problem at hand.</p>
<p><strong>ONE MORE CUP OF COFFEE</strong></p>
<p>You could say that after the PHP port, I developed <a href="http://www.youtube.com/watch?v=QqPiJ0L7YmY">shpillka in my ganektagazoink</a>,  but that&#8217;s besides the point. No, that is the point. I had the bug. The  bug to learn new languages and re-learn old languages. So, before  coming to Ruby, I developed in Java for nearly 15 years, with a 3 year  stint of C# in there as well. And so this past weekend I ported the  leaderboard library to Java and the <a href="https://github.com/agoragames/java-leaderboard">java-leaderboard</a> library was born. I also took the steps there to figure out how to  properly release that as a library that other Java developers could  integrate using Maven. Thankfully, after 3 or 4 days of what seems like  more process than progress to me, I was able to get the java-leaderboard  library out to the world. <a href="http://search.maven.org/#search|ga|1|leaderboard">Search for it</a> and you&#8217;ll find it.</p>
<p><strong>MY ANACONDA DON&#8217;T WANT NONE UNLESS &#8230;</strong></p>
<p>The PHP port was also inspiration for two colleagues to release the <a href="https://github.com/agoragames/python-leaderboard">python-leaderboard</a> package.</p>
<p><strong>COMFORTABLY NUMB<br />
</strong></p>
<p>It felt really good to work in a new language and to re-connect with  an old language. And for whatever reason, I need that mental disruption  to continue. And so it shall. My current in-progress ports of the  leaderboard library are to <a href="http://nodejs.org/">NodeJS</a> and <a href="http://golang.org/">Go</a>. Porting the leaderboard library works for me because of a number of factors:</p>
<p>1. It is well-defined in terms of behavior/functionality.</p>
<p>2. It requires integration of a service and a service client library.</p>
<p>3. It requires some knowledge of control statements, types and higher-level data structures.</p>
<p>4. It has a well-defined set of tests.</p>
<p>I&#8217;ve had to become comfortable with being uncomfortable. New syntax, new packaging, new test framework, new release mechanism. Conformity be damned!</p>
<p><a href="../wp-content/uploads/2011/06/moms_minivan.jpg"><img src="../wp-content/uploads/2011/06/moms_minivan-300x240.jpg" alt="" width="300" height="240" /></a></p>
<p><strong>FIN</strong></p>
<p>I would encourage anyone who feels they&#8217;re set in their ways or in  need of a change to undertake a similar endeavor. I can imagine this  applies to any number of disciplines in the video game industry. Find a  well-defined, testable problem that you&#8217;ve solved again and again and  solve it differently.</p>
<p>It&#8217;s that simple.</p>
<p>You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">@CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/06/30/re-education-through-leaderboards/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>I&#8217;ll Show You Mine If You Show Me Yours ;)</title>
		<link>http://www.altdevblogaday.com/2011/06/14/ill-show-you-mine-if-you-show-me-yours/</link>
		<comments>http://www.altdevblogaday.com/2011/06/14/ill-show-you-mine-if-you-show-me-yours/#comments</comments>
		<pubDate>Tue, 14 Jun 2011 04:04:37 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
		
		<guid isPermaLink="false">http://altdevblogaday.org/?p=8496</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>This post is EXACTLY* what you think it&#8217;s about.</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p>&#160;</p>
<p><a href="http://www.altdevblogaday.com/2011/06/14/ill-show-you-mine-if-you-show-me-yours/" class="more-link">Read more on I&#8217;ll Show You Mine If You Show Me Yours ;)&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>This post is EXACTLY* what you think it&#8217;s about.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span id="more-8496"></span></p>
<p><strong>* NOT EXACTLY</strong></p>
<p>Gotcha! But, you&#8217;re still reading, so what does that say about YOU? ;)</p>
<p>I write 2 types of posts here on AltDevBlogADay, one that is more developer-oriented and one that is not. Each type of post is gaming-related, however. This post falls into the latter type.</p>
<p><del>I couldn&#8217;t find the online article(s) from awhile back (maybe a couple of years or so?) where whatever site had famous or more well-known game developers post photos of where they game. If you know of the article(s) I&#8217;m talking about, please link me in the comments.</del> One of our readers found it, <a href="http://web.archive.org/web/20100630155643/http://kotaku.com/343590/work-and-play-a-peek-inside-the-lives-of-gamings-greatest">Work and Play: A Peek Inside the Lives of Gaming&#8217;s Greatest</a>.</p>
<p>In any event, I&#8217;m not famous, but I have a pretty baller setup as far as where I game and my gaming &#8220;infrastructure&#8221;. So, I&#8217;m going to show that to you now.</p>
<p>I do most of my gaming in the master bedroom. 42&#8243; HDTV. PlayStation 3. Wii. PlayStation 2. Xbox 360. You&#8217;ll notice, or not, the wires run behind a very tidy wall conduit so that the wires aren&#8217;t exposed. The Xbox 360 power unit is actually zip-tied underneath the glass platform. As you can tell, I mostly play Xbox 360 games &#8230; mostly. I only play PlayStation 3 exclusives if I do buy and play PlayStation 3 games. The Wii never gets used except for when the nieces or nephews come over. The PlayStation 2 is still hooked up so that I can play Ico or Shadow of the Colossus.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/06/Czarnecki-MBR.jpg"><img class="alignnone size-medium wp-image-8509" src="http://altdevblogaday.com/wp-content/uploads/2011/06/Czarnecki-MBR-178x300.jpg" alt="" width="178" height="300" /></a></p>
<p>The master bedroom remote is also pretty sweet. As you can see from the photo below, the Xbox 360 is hotkey&#8217;d in the remote menu. Click on it and it will switch the TV for you to Xbox 360 mode. Similar hotkeys exist for the other gaming systems.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/06/Czarnecki-MBR-Remote.jpg"><img class="alignnone size-medium wp-image-8510" src="http://altdevblogaday.com/wp-content/uploads/2011/06/Czarnecki-MBR-Remote-178x300.jpg" alt="" width="178" height="300" /></a></p>
<p>The great room is where I can move a system to if I want a more immersive gaming experience. I own an extra set of video cables and power cords so that I can move a system down here without moving those items from the master bedroom. 45&#8243; HDTV. Front speaker under-mounted on the TV with a custom bracket. Sub-woofer (hidden). Rear speakers (not pictured) mounted in the upper walls to the left and right of the oversized 2-person chair I was sitting in when taking the photo. This is where I played both Dead Space and Dead Space 2, only after dark, and only with the lights completely off. Frightened much? This is also where we had an epic Gears of War 2 Horde session with folks from work, when at 5 AM our CFO at the time said, &#8220;Guys, I need to go. My son is going to get up in an hour.&#8221;</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/06/Czarnecki-Great-Room.jpg"><img class="alignnone size-medium wp-image-8507" src="http://altdevblogaday.com/wp-content/uploads/2011/06/Czarnecki-Great-Room-178x300.jpg" alt="" width="178" height="300" /></a></p>
<p>The great room remote also has functions to switch the system into game mode.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/06/Czarnecki-Great-Room-Remote1.jpg"><img class="alignnone size-medium wp-image-8536" src="http://altdevblogaday.com/wp-content/uploads/2011/06/Czarnecki-Great-Room-Remote1-300x178.jpg" alt="" width="300" height="178" /></a></p>
<p><strong> </strong></p>
<p>Now that I&#8217;ve showed you mine, so to speak &#8230; it&#8217;s your turn ;)<strong><br />
</strong></p>
<p><strong>FIN</strong></p>
<p>Did I actually expose myself? No.</p>
<p>Did I actually expose where I game? Yes.<strong> </strong></p>
<p>Leave a comment and link to a photo of where you game. If I get enough photos or interest, I&#8217;ll use my next non-developer AltDevBlogADay post to expose you, so to speak, on the Internet. Please keep it clean. This blog is rated E for Everyone!</p>
<p>You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/06/14/ill-show-you-mine-if-you-show-me-yours/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Continuous Notification</title>
		<link>http://www.altdevblogaday.com/2011/06/01/continuous-notification/</link>
		<comments>http://www.altdevblogaday.com/2011/06/01/continuous-notification/#comments</comments>
		<pubDate>Wed, 01 Jun 2011 01:20:06 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
		
		<guid isPermaLink="false">http://altdevblogaday.org/?p=7228</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>You&#8217;ve got your <a href="http://en.wikipedia.org/wiki/Continuous_integration">continuous integration</a> (CI) server setup so that whenever someone checks in an item (code, asset, configuration file, etc.) to your repository, a build process is started, tests are run, the build passes or fails, and then what? If your build passes or fails, who gets notified? Enter continuous notification.</p>
<p><a href="http://www.altdevblogaday.com/2011/06/01/continuous-notification/" class="more-link">Read more on Continuous Notification&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>You&#8217;ve got your <a href="http://en.wikipedia.org/wiki/Continuous_integration">continuous integration</a> (CI) server setup so that whenever someone checks in an item (code, asset, configuration file, etc.) to your repository, a build process is started, tests are run, the build passes or fails, and then what? If your build passes or fails, who gets notified? Enter continuous notification.</p>
<p><strong>CONTINUOUS NOTIFICATION</strong></p>
<p>Continuous notification is not a new concept. It seems logical to me that you send out notifications on the status of the build in your continuous integration server. Here are ways you might want to go about notifying your team.</p>
<p>E-mail: This is the most passive form of notification and any continuous integration server worth a damn will support build notification via e-mail. You&#8217;ve probably already got a team e-mail list per project for the various projects being built by your continuous integration server. Make sure the team knows the build failed. You can optionally also send an e-mail to the individual who broke the build, but at that point it&#8217;s just insult to injury. Developers may not be checking e-mail on a regular basis, so consider adding additional continuous notifications.</p>
<p>Group chat: If your teams use a group chat like IRC, Campfire, HipChat, Yammer, or whatever, your continuous integration server might support notification for these services. This is a more direct form of continuous notification as opposed to e-mail. You will most likely interrupt developer conversations. Good. If you notify a separate build notification room, developers will never ever join that room. Ever. It also means there&#8217;s a formal record of the build status as these services typically support day-to-day transcripts.</p>
<p>Instant message: The build fails and the developer gets an instant message from the continuous integration server letting them know as such. This is one of the most direct forms of continuous notification short of the continuous integration server notifying Johnny 5 who subsequently comes over to your desk and says to you, &#8220;Los Locos kick your ass. Los Locos kick your face. Los Locos kick your balls INTO OUTER SPACE!&#8221;</p>
<p><strong>FIN</strong></p>
<p>Use your continuous integration server to notify your team on the status of your build(s). That is all.</p>
<p>Maybe this should have been the TL;DR?</p>
<p>You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/06/01/continuous-notification/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>What Makes You &#8220;Tick&#8221;?</title>
		<link>http://www.altdevblogaday.com/2011/05/16/what-makes-you-tick/</link>
		<comments>http://www.altdevblogaday.com/2011/05/16/what-makes-you-tick/#comments</comments>
		<pubDate>Mon, 16 May 2011 09:00:01 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
		
		<guid isPermaLink="false">http://altdevblogaday.org/?p=5908</guid>
		<description><![CDATA[<p>I&#8217;m off to a conference this week, so I need to keep this blog post very short. I promise to write a more lengthy blog post before my next scheduled blog post to make up for this one.</p>
<p><a href="http://www.altdevblogaday.com/2011/05/16/what-makes-you-tick/" class="more-link">Read more on What Makes You &#8220;Tick&#8221;?&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p>I&#8217;m off to a conference this week, so I need to keep this blog post very short. I promise to write a more lengthy blog post before my next scheduled blog post to make up for this one.</p>
<p>Do all programmers have some kind of &#8220;tick&#8221; when they&#8217;re thinking at the keyboard? Mine is to tap the CAPS LOCK key on and off a few times. I use it as a way to still be connected in some way to the keyboard. I do it in writing blog posts as well. I&#8217;m doing it right now. But, you&#8217;d never know it.</p>
<p>What makes you &#8220;tick&#8221;?</p>
<p>You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">@CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/05/16/what-makes-you-tick/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>To Catch A Completionist</title>
		<link>http://www.altdevblogaday.com/2011/04/16/to-catch-a-completionist/</link>
		<comments>http://www.altdevblogaday.com/2011/04/16/to-catch-a-completionist/#comments</comments>
		<pubDate>Sat, 16 Apr 2011 04:16:52 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
		
		<guid isPermaLink="false">http://altdevblogaday.org/?p=4107</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>Around the studio, it&#8217;s a running joke that I&#8217;m the guy who beats video games. And it&#8217;s true. I love to play and beat video games. It might be a Sunday afternoon, a few days, or a month. Eventually I&#8217;ll start off in our AM standup with, &#8220;Oh, I just beat &#8230;&#8221; If there&#8217;s a game coming out, chances are I&#8217;ll be playing it. And by the time you&#8217;ve gotten around to playing it, I&#8217;ve beaten it. However in this post, I briefly analyze all of the video games where I have all of the achievements and try to assess why those games stood out as being &#8220;worthy&#8221; of that extra effort. These are a subset of the 100+ games that I own.</p>
<p><a href="http://www.altdevblogaday.com/2011/04/16/to-catch-a-completionist/" class="more-link">Read more on To Catch A Completionist&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>Around the studio, it&#8217;s a running joke that I&#8217;m the guy who beats video games. And it&#8217;s true. I love to play and beat video games. It might be a Sunday afternoon, a few days, or a month. Eventually I&#8217;ll start off in our AM standup with, &#8220;Oh, I just beat &#8230;&#8221; If there&#8217;s a game coming out, chances are I&#8217;ll be playing it. And by the time you&#8217;ve gotten around to playing it, I&#8217;ve beaten it. However in this post, I briefly analyze all of the video games where I have all of the achievements and try to assess why those games stood out as being &#8220;worthy&#8221; of that extra effort. These are a subset of the 100+ games that I own.</p>
<p><strong>STICKS AND STONES MAY BREAK MY BONES, BUT &#8230;</strong></p>
<p>I wouldn&#8217;t consider myself an &#8220;Achievement Hunter&#8221; or a &#8220;Cheevo Whore&#8221;, but those are two terms that may come to mind as you read this blog post. None of the games I played through to completion were games I played just to get the full gamerscore.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-6.59.03-PM.png"><img class="alignnone size-medium wp-image-4108" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-6.59.03-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>I take that back because first game I got all the achievements on was, &#8220;Avatar: The Last Airbender: The Burning Earth&#8221;. One might consider it a completionist&#8217;s &#8220;gateway drug&#8221;. Let&#8217;s face it, <a href="http://www.youtube.com/watch?v=W6bKh47xxNc">it takes less than 3 minutes to get all the achievements and 1000G</a>. What do I have to say for myself for this transgression? I never inhaled.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.22.33-PM.png"><img class="alignnone size-medium wp-image-4110" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.22.33-PM-300x45.png" alt="" width="300" height="45" /></a></p>
<p>This is the one Pac-Man game I&#8217;ve played from XBLA. Am I the only one who thought Ms. Pac-Man was better than the original Pac-Man in some ways? It had those intermission &#8220;cut scenes&#8221; that at least told a small story.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.30.47-PM.png"><img class="alignnone size-medium wp-image-4111" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.30.47-PM-300x47.png" alt="" width="300" height="47" /></a></p>
<p>3 words. Doritos. Dinosaurs. Destruction. It&#8217;s a shame the game isn&#8217;t available from XBLA anymore.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.34.28-PM.png"><img class="alignnone size-medium wp-image-4112" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.34.28-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>I&#8217;m not surprised UNO translated this well into a video game. It&#8217;s such a fun casual game that you can play to wind down an evening.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.38.03-PM.png"><img class="alignnone size-medium wp-image-4113" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.38.03-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>One of my friends on XBOX Live turned me on to this game. I guess it was developed by 3 interns at Microsoft, but is a great example of a casual co-op game.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.41.05-PM.png"><img class="alignnone size-medium wp-image-4114" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.41.05-PM-300x45.png" alt="" width="300" height="45" /></a></p>
<p>Another game sponsored by Doritos and another easy set of achievements. Almost too easy. It&#8217;s like Doritos wants to bump up your gamerscore each year. For free.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.11.19-PM.png"><img class="alignnone size-medium wp-image-4117" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.11.19-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>Zombies. Lots and lots of zombies. As far as a zombie game that you don&#8217;t necessarily have to think about, it&#8217;s fun. Although I think that the character resemblance to characters from Left 4 Dead isn&#8217;t any coincidence. And apparently zombies are attracted to teddy bears. Who knew?!</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.18.34-PM.png"><img class="alignnone size-medium wp-image-4118" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.18.34-PM-300x45.png" alt="" width="300" height="45" /></a></p>
<p>My only gripe with Stacking is that it wasn&#8217;t a full-fledged retail game. I loved and laughed every second I played this game. It was a treat trying to figure out what dolls you needed to discover, what combination of dolls you had to use to solve puzzles in different ways, and what &#8220;special things&#8221; you could do to other dolls. It is one of the best &#8220;short&#8221; games I&#8217;ve played in awhile. I really should pickup Costume Quest now.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.10.03-PM.png"><img style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-7.10.03-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>I  have a love/hate relationship with the Assassin&#8217;s Creed series. I  love  the story. I hate the game controls. For me, I think they really  hit the  sweet spot with that franchise with Assassin&#8217;s Creed:  Brotherhood. I  played the multiplayer in that game for about a week  straight, 8+ hours a  day, this past December. But, back to Assassin&#8217;s  Creed 2. Most of the  achievements were either story-related. So it was  refreshing to try for  these achievements that unlocked more pieces of  the Assassin&#8217;s Creed story.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.26.36-PM.png"><img class="alignnone size-medium wp-image-4121" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.26.36-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>The Left 4 Dead series is the best video game featuring zombies I have played. Ever. Left 4 Dead was the first game I played on XBOX where I cared about the people I was playing with. It&#8217;s all about teamwork. I can remember the weekend where I finished the Blood Harvest and Death Toll campaigns on expert to finish the achievement where you survive all campaigns on expert. It was a rush. I still have one of the best legitimate times on the leaderboard for survival mode on the &#8220;The Church&#8221; map (one of the hardest survival maps IMO). I&#8217;d drop any other game to play Left 4 Dead if someone asked.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.35.19-PM.png"><img class="alignnone size-medium wp-image-4122" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.35.19-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>I actually left the studio early on the day Left 4 Dead 2 came out to play. I played it for nearly 18 hours straight and had 34 of the 50 achievements before I had to hop on a train for a company trip to New York City. It was an awesome trip. We had one meeting in the afternoon, but before that I organized a group of folks where we went to the top of the Empire State Building, the NY Public Library for a map exhibition, the Nintendo World Store, Katz&#8217;s Deli, and finally the Magnolia Bakery. All the time I thought, &#8220;I&#8217;ll be OK if the zombie apocalypse hits.&#8221;</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.41.13-PM.png"><img class="alignnone size-medium wp-image-4123" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.41.13-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>I&#8217;ve probably played through the entire Borderlands campaign on Playthrough 1 and Playthrough 2 maybe 8 or 9 times? I&#8217;ve lost count all the times I&#8217;ve helped other folks out. All the DLCs, except for maybe Mad Moxxi&#8217;s Underdome Riot (which is just repetitive) are fantastic, especially The Secret Armory of General Knoxx. Ice cream soldiers anyone? Characters and character progression: awesome. Driving: awesome. Loot: awesome. Story and dialogue: awesome. Borderlands is simply fun.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.45.28-PM.png"><img class="alignnone size-medium wp-image-4124" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.45.28-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>Bulletstorm, for me, reinvigorated the FPS genre. It was so much fun going through the Echoes and re-playing parts of the campaigns to try and get the best score possible. All the ways in which I could use the environment and the unique skill shots make it a different game each time I play it. I played Gears of War 2 the other night on horde mode. It felt so repetitive and boring in comparison.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.50.06-PM.png"><img class="alignnone size-medium wp-image-4125" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.50.06-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>Dead Space may be the best survival horror game I&#8217;ve played. I only played Dead Space on my surround sound system in the dark. It freaked me the fuck out. Always. Once I knew Dead Space 2 was official, I felt I had to complete the game. #altmanbepraised</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.54.02-PM.png"><img class="alignnone size-medium wp-image-4126" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.54.02-PM-300x45.png" alt="" width="300" height="45" /></a></p>
<p>Dead Space 2 may have one of the hardest achievements in any game. &#8220;Hard to the Core&#8221;. You only get 3 saves and if you die, you go back to your last save. #protip: After the disc swap, if you die, the game will send you back to the beginning of Disc 2 unless you turn off your XBOX or end your game. I left my XBOX on for a day. Once I got to the final fight, I psyched myself up for a good 15 minutes. It was one of the best feelings beating this game. Looking forward to Dead Space 3 if that ever becomes a thing.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.59.34-PM.png"><img class="alignnone size-medium wp-image-4127" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-15-at-11.59.34-PM-300x46.png" alt="" width="300" height="46" /></a></p>
<p>BioShock is the best video game I have ever played. Ever. My reasons there are deserving of a blog post in itself. Suffice it to say, I went a little cray cray towards the end. I present to you, <a href="http://www.flickr.com/photos/davidczarnecki/1430008396/in/photostream/">BioShock Notes</a>. I took meticulous (bordering on insanity) notes during BioShock. This is the final sheet and I got to the point where each save was described by a set of acronyms as to what transpired since the last save. Once BioShock 2 was officially announced, I was actually fearful of going back to finish off the last achievements for BioShock for fear of ruining my initial experience.</p>
<p><a href="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-16-at-12.04.16-AM.png"><img class="alignnone size-medium wp-image-4128" style="border: 1px solid black" src="http://altdevblogaday.com/wp-content/uploads/2011/04/Screen-shot-2011-04-16-at-12.04.16-AM-300x45.png" alt="" width="300" height="45" /></a></p>
<p>I relished at the thought of being able to go back to Rapture for BioShock 2. Although not as emotionally compelling as the original BioShock IMO, it was still a fantastic game. Minerva&#8217;s Den may be the geekiest DLC ever.</p>
<p><strong>FIN</strong></p>
<p>Video games are fun. I love to play and beat video games. You&#8217;ve gotten a glimpse into the video games I&#8217;ve wholly beaten. What video games have you beat? Why?</p>
<p>You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">@CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/04/16/to-catch-a-completionist/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I Am Data (And So Can You!)</title>
		<link>http://www.altdevblogaday.com/2011/04/01/i-am-data-and-so-can-you/</link>
		<comments>http://www.altdevblogaday.com/2011/04/01/i-am-data-and-so-can-you/#comments</comments>
		<pubDate>Fri, 01 Apr 2011 05:00:02 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
		
		<guid isPermaLink="false">http://altdevblogaday.org/?p=2946</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>I share my thoughts on data collection in video games. Examples of data collection might include performance data at the end of a Guitar Hero or Rock Band song or match data at the end of a Black Ops or Halo:Reach match or score and birds left at the end of an Angry Birds level. This is not an exhaustive list. YMMV.</p>
<p><a href="http://www.altdevblogaday.com/2011/04/01/i-am-data-and-so-can-you/" class="more-link">Read more on I Am Data (And So Can You!)&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>I share my thoughts on data collection in video games. Examples of data collection might include performance data at the end of a Guitar Hero or Rock Band song or match data at the end of a Black Ops or Halo:Reach match or score and birds left at the end of an Angry Birds level. This is not an exhaustive list. YMMV.</p>
<p><strong>YOU GOT A FAST CAR</strong></p>
<p>But is it fast enough so we can fly away? There are times when your data collection is going to have to be as fast as possible. Launch day of your game and the week after launch, holidays like Thanksgiving and Christmas and Hanukkah, school breaks/vacations, evenings and weekends, etc. Make some worst-case scenario estimates on data traffic based on prior experience or Ouija board or however, but make sure that your data collection can scale at these peak times. If you need to spin up servers temporarily for these times, do it. This is also an opportunity to investigate micro frameworks that reduce application complexity and that may allow you to be as direct as possible in collecting game data into a database.</p>
<p><strong>EGGS AND BASKETS</strong></p>
<p>I haven&#8217;t looked myself, but I&#8217;m sure there&#8217;s some seedy, alternate meaning to the phrase, &#8220;Don&#8217;t put all your eggs in one basket&#8221; (Urban Dictionary: NOT SAFE). The same applies to data and databases. Don&#8217;t put all your data in one database. If you are going to be writing data from your game into a database, a good rule of thumb is a database per title+platform. If you use a single database for all your game data across platforms, when that one database &#8220;shits the bed&#8221; (Urban Dictionary: SAFE), and databases will eventually &#8220;shit the bed&#8221;, data collection will effectively be stopped for all titles+platforms. The single database also makes it a pain to do data archival when you want to move old entries into long-term storage. And a larger, single database means database backups are going to be slower.</p>
<p><strong>U GOT THE LOOK(UP)</strong></p>
<p>If you&#8217;re going to be looking up game data from your database, make sure you are using indexed fields. Any data retrieval resulting in a &#8220;full-table scan&#8221;, as the size of your data size grows, so does the time it takes for you to look up that data. This happened to me around Thanksgiving 2008 where collected game data, used for online tournaments, was taking longer than usual to post and affect the tournaments. This resulted in a complete rewrite of a data collector, that has since (knock on wood &#8230; hehehehe wood), performed flawlessly and that scales automatically during peak periods.</p>
<p><strong>DON&#8217;T FEAR THE REAPER</strong></p>
<p>Whether you&#8217;re working with a middleware provider to retrieve data or you&#8217;re doing it internally, presumably you&#8217;ll have some process to collect and do something with that data. I like to affectionately call these processes, &#8220;reapers&#8221;. Without knowing what data you have to work with, I can say this, make sure your reaper saves its state while running. Reapers, whether it be from solar flares or maxed out memory limits, will fail and they will need to be restarted. Without some bootstrap knowledge of where reaping left off, this may result in unnecessary processing of already processed data.</p>
<p><strong>BATCH THAT THANG UP </strong></p>
<p>Ensure that you use reasonable limits in the amount of game data that you pull at any one time from your database. Let&#8217;s say your reaper &#8220;shits the bed&#8221; on a Friday and you don&#8217;t notice until Monday and you need to restart the reaper. Furthermore, 1,000,000 (1 MILLION) new game data entries have been collected since your reaper stopped. Batching these unprocessed entries in groups of 1,000 (1 THOUSAND) will help to make sure you&#8217;re not trying to retrieve too much data in any one cycle.</p>
<p><strong>USE A REASONABLE DATA FORMAT</strong></p>
<p>It&#8217;s 2011. JSON is the shit and XML is dead, right? Whatever. Pick a reasonable, structured data format in which to package your game data.</p>
<p>XML:</p>
<p>&lt;game&gt;<br />
&lt;player&gt;<br />
&lt;name&gt;BronxZoosCobra&lt;/name&gt;<br />
&lt;score&gt;1000069&lt;/score&gt;<br />
&lt;/player&gt;<br />
&lt;/game&gt;</p>
<p>JSON:</p>
<p>{<br />
&#8220;game&#8221;:{<br />
&#8220;player&#8221;:{<br />
&#8220;name&#8221;:&#8217;BronxZoosCobra&#8217;,<br />
&#8220;score&#8221;:1000069<br />
}<br />
}<br />
}</p>
<p><strong>SIZE MATTERS<br />
</strong></p>
<p>I said it. You better make sure all your data is going to fit in your database fields. Don&#8217;t assume that an 8K database field in which to store match data, for example, is reasonable. Or maybe it is reasonable. But did you validate that a game data record with 16 players from a match with all game data statistics maxed out will fit into an 8K database field? If not, dummy up the data, try to stick that record in the database, and see if it fits. If not, increase the size of the database field. It&#8217;s that easy. No pills or creams required.</p>
<p><strong>FIN</strong></p>
<p>Data collection from video games requires some finesse to get right. Be quick to process, distribute your load, index your lookups, save state in processing, batch process, structure the data and size your storage appropriately.</p>
<p>Also, happy April Fool&#8217;s Day.</p>
<p>You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/04/01/i-am-data-and-so-can-you/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>What are you playing tonight?</title>
		<link>http://www.altdevblogaday.com/2011/03/18/what-are-you-playing-tonight/</link>
		<comments>http://www.altdevblogaday.com/2011/03/18/what-are-you-playing-tonight/#comments</comments>
		<pubDate>Fri, 18 Mar 2011 01:15:40 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
		
		<guid isPermaLink="false">http://altdevblogaday.org/?p=2067</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>About once a week, I like to ask on the Twitter, &#8220;What are you playing tonight?&#8221; I&#8217;m generally interested to hear about the games that people are playing. I play video games &#8230; ok, a LOT of video games. I figure it&#8217;s a nice balance to the development work on games. So, here&#8217;s what I&#8217;ve played over the past couple of years, what I&#8217;ve played this year and what I will be playing.</p>
<p><a href="http://www.altdevblogaday.com/2011/03/18/what-are-you-playing-tonight/" class="more-link">Read more on What are you playing tonight?&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>About once a week, I like to ask on the Twitter, &#8220;What are you playing tonight?&#8221; I&#8217;m generally interested to hear about the games that people are playing. I play video games &#8230; ok, a LOT of video games. I figure it&#8217;s a nice balance to the development work on games. So, here&#8217;s what I&#8217;ve played over the past couple of years, what I&#8217;ve played this year and what I will be playing.</p>
<p>So, what are YOU playing tonight?</p>
<p><span id="more-2067"></span><strong>THE NAME OF THE GAME</strong></p>
<p>Unless otherwise indicated (*), I have completed the entire game or DLC. I also probably have most, if not all, of the achievements (or trophies) in the game.</p>
<p><span style="text-decoration: underline">2009</span></p>
<p>360: Silent Hill Homecoming (*), F.E.A.R, F.E.A.R. 2 (Project Origin), Halo Wars (*), Call of Duty: World at War, Guitar Hero: Metallica, Mirror&#8217;s Edge, RESIDENT EVIL 5, Guitar Hero: Hits, Batman: Arkham Asylum, Ghostbusters, Fallout 3, [PROTOTYPE], Section 8, Guitar Hero 5, Band Hero, Guitar Hero: Van Halen, Halo 3: ODST, ZOMBIE APOCALYPSE, Brütal Legend, Borderlands, Left 4 Dead 2, Modern Warfare 2, Assassin&#8217;s Creed 2, Borderlands &#8211; The Zombie Island of Dr. Ned DLC, Borderlands &#8211; Mad Moxxi&#8217;s Underdome Riot DLC</p>
<p>PS3: inFamous, Uncharted (Drake&#8217;s Fortune), Uncharted 2 (Among Thieves), Ratchet &amp; Clank Future: Tools of Destruction</p>
<p>DS: Treasure World, Scribblenauts</p>
<p><span style="text-decoration: underline">2010</span></p>
<p>360: Darksiders, Mass Effect 2, BioShock 2, Dante&#8217;s Inferno, Borderlands &#8211; The Secret Armory of General Knoxx DLC, Battlefield: Bad Company 2, Alan Wake, Red Dead Redemption, Blur, BioShock 2 &#8211; Rapture Metro Pack DLC, Naughty Bear, LIMBO, BioShock 2 &#8211; Protector Trials Pack DLC, BioShock 2 &#8211; Minerva&#8217;s Den DLC, Plants vs. Zombies, Halo: Reach, Guitar Hero: Warriors of Rock, Borderlands &#8211; Claptrap&#8217;s New Robot Revolution DLC, Lucha Libre AAA: Héroes del Ring (*), Fallout: New Vegas, Super Meat Boy (*), Rock Band 3 (*), Dead Space Ignition, Call of Duty: Black Ops, ilomilo, Assassin&#8217;s Creed: Brotherhood</p>
<p>PS3: God of War 3</p>
<p>DS: Super Scribblenauts</p>
<p><span style="text-decoration: underline">2011</span></p>
<p>360: Fable 3, Dead Space 2, Bulletstorm</p>
<p>PS3: LittleBigPlanet 2</p>
<p><span style="text-decoration: underline">2011 Pre-Order List</span></p>
<p>Mortal Kombat, Portal 2, Brink, ICO and Shadow of the Colossus Collection</p>
<p><strong>FIN</strong></p>
<p>I didn&#8217;t intend for this to simply be a post listing out a bunch of video game titles, but &#8230; well &#8230; it is. I love playing video games.</p>
<p>So, what are YOU playing tonight? Tonight I&#8217;ll be playing more Bulletstorm Anarchy mode.</p>
<p>You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">@CzarneckiD</a>.</p>
<p><strong>PS</strong></p>
<p>Contrary to what you might think in this post, I do have a life outside of video games. I like going out to eat where <a href="http://www.flickr.com/photos/davidczarnecki/sets/72157624785506263/">you can&#8217;t count the number of courses on your fingers and toes</a>, actively write open source software (<a href="https://github.com/czarneckid">personal</a>, <a href="https://github.com/agoragames">work</a>, <a href="https://github.com/BrightcoveOS/Ruby-MAPI-Wrapper">other</a>), recently got into <a href="http://www.flickr.com/photos/davidczarnecki/sets/72157624156531812/">beekeeping</a> and love <a href="http://www.flickr.com/photos/davidczarnecki/sets/72157623585355124/with/4419212227/">snowboarding</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/03/18/what-are-you-playing-tonight/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Meta Leaderboards</title>
		<link>http://www.altdevblogaday.com/2011/03/02/meta-leaderboards/</link>
		<comments>http://www.altdevblogaday.com/2011/03/02/meta-leaderboards/#comments</comments>
		<pubDate>Wed, 02 Mar 2011 14:25:48 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
		
		<guid isPermaLink="false">http://altdevblogaday.org/?p=1440</guid>
		<description><![CDATA[<p><strong>TL;DR</strong></p>
<p>You read my <a href="http://altdevblogaday.com/2011/01/31/leaderboards-a-how-to-guide/">Leaderboards: A How-To Guide</a> post right? I revealed a dirty little secret about this world &#8230; we still don&#8217;t have flying cars. But, we do have a good way of creating leaderboards in video games. At least I think so. I want to continue on the leaderboard love train and expand on a concept I call &#8220;Meta Leaderboards&#8221;. Traditionally, leaderboards rank players using one criteria, e.g. XP,  kills, etc. What if you wanted to combine leaderboards to form a larger, aggregate leaderboard? I’m going to show you  how to do that.</p>
<p><a href="http://www.altdevblogaday.com/2011/03/02/meta-leaderboards/" class="more-link">Read more on Meta Leaderboards&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>TL;DR</strong></p>
<p>You read my <a href="http://altdevblogaday.com/2011/01/31/leaderboards-a-how-to-guide/">Leaderboards: A How-To Guide</a> post right? I revealed a dirty little secret about this world &#8230; we still don&#8217;t have flying cars. But, we do have a good way of creating leaderboards in video games. At least I think so. I want to continue on the leaderboard love train and expand on a concept I call &#8220;Meta Leaderboards&#8221;. Traditionally, leaderboards rank players using one criteria, e.g. XP,  kills, etc. What if you wanted to combine leaderboards to form a larger, aggregate leaderboard? I’m going to show you  how to do that.</p>
<p><span id="more-1440"></span><strong>WHOOMP! (THERE IT IS)</strong></p>
<p>Let’s say you’ve got a game and its multiplayer mode can be played  across 5 maps. We’ll also simplify things and say that we’re only  ranking players on each map on XP gained when finishing the map. If you  want to generate a leaderboard of players ranked by XP who have  played  in any of the maps, you would need to perform a merge of each of  the  leaderboards for the 5 maps. If you want to generate a leaderboard of  players ranked by XP who have played in each of the maps, you would need  to perform an intersection of each of the leaderboards for the 5 maps.</p>
<p>This functionality is now present in the <a href="https://github.com/agoragames/leaderboard">Ruby leaderboard gem</a>.</p>
<p>Check it to wreck it, let&#8217;s begin!</p>
<p><span style="text-decoration: underline">Generate a leaderboard of players ranked by XP who have played in any of the maps</span>:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="code"><pre class="ruby" style="font-family:monospace;">ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_1_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_1_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#, @host=&quot;localhost&quot;, @redis_options={:host=&gt;&quot;localhost&quot;, :port=&gt;6379}&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_2_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_2_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#, @host=&quot;localhost&quot;, @redis_options={:host=&gt;&quot;localhost&quot;, :port=&gt;6379}&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_3_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_3_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#, @host=&quot;localhost&quot;, @redis_options={:host=&gt;&quot;localhost&quot;, :port=&gt;6379}&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_4_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_4_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#, @host=&quot;localhost&quot;, @redis_options={:host=&gt;&quot;localhost&quot;, :port=&gt;6379}&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_5_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_5_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#, @host=&quot;localhost&quot;, @redis_options={:host=&gt;&quot;localhost&quot;, :port=&gt;6379}&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_1_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_1'</span>, <span style="color:#006666;">10</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_2_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_2'</span>, <span style="color:#006666;">7</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_3_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_3'</span>, <span style="color:#006666;">7</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_4_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_4'</span>, <span style="color:#006666;">22</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_5_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_5'</span>, <span style="color:#006666;">3</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> map_1_xp_lb.<span style="color:#9900CC;">merge_leaderboards</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'any_maps_xp_lb'</span>, <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'map_2_xp'</span>, <span style="color:#996600;">'map_3_xp'</span>, <span style="color:#996600;">'map_4_xp'</span>, <span style="color:#996600;">'map_5_xp'</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">5</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> any_maps_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'any_maps_xp_lb'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#, @host=&quot;localhost&quot;, @redis_options={:host=&gt;&quot;localhost&quot;, :port=&gt;6379}&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> any_maps_xp_lb.<span style="color:#9900CC;">total_members</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">5</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.8.7<span style="color:#006600; font-weight:bold;">-</span>p302 <span style="color:#006600; font-weight:bold;">&gt;</span> any_maps_xp_lb.<span style="color:#9900CC;">leaders</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#123;</span>:rank<span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">1</span>, <span style="color:#ff3333; font-weight:bold;">:member</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#996600;">&quot;member_4&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:score</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">22.0</span><span style="color:#006600; font-weight:bold;">&#125;</span>, <span style="color:#006600; font-weight:bold;">&#123;</span>:rank<span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">2</span>, <span style="color:#ff3333; font-weight:bold;">:member</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#996600;">&quot;member_1&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:score</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">10.0</span><span style="color:#006600; font-weight:bold;">&#125;</span>, <span style="color:#006600; font-weight:bold;">&#123;</span>:rank<span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">3</span>, <span style="color:#ff3333; font-weight:bold;">:member</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#996600;">&quot;member_3&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:score</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">7.0</span><span style="color:#006600; font-weight:bold;">&#125;</span>, <span style="color:#006600; font-weight:bold;">&#123;</span>:rank<span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">4</span>, <span style="color:#ff3333; font-weight:bold;">:member</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#996600;">&quot;member_2&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:score</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">7.0</span><span style="color:#006600; font-weight:bold;">&#125;</span>, <span style="color:#006600; font-weight:bold;">&#123;</span>:rank<span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">5</span>, <span style="color:#ff3333; font-weight:bold;">:member</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#996600;">&quot;member_5&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:score</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">3.0</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#93;</span></pre></td></tr></table></div>

<p>The default behavior for the merge leaderboards call is to sum the scores for members present in any of the leaderboards. You could also take a maximum or minimum score for members present in any of the leaderboards to generate a high score (or low score) leaderboard across the different maps.</p>
<p><span style="text-decoration: underline">Generate a leaderboard of  players ranked by XP who have played in each of the maps</span>:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
</pre></td><td class="code"><pre class="ruby" style="font-family:monospace;">ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_1_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_1_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#&quot;localhost&quot;, :port=&gt;6379}, @redis_connection=#&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_2_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_2_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#&quot;localhost&quot;, :port=&gt;6379}, @redis_connection=#&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_3_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_3_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#&quot;localhost&quot;, :port=&gt;6379}, @redis_connection=#&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_4_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_4_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#&quot;localhost&quot;, :port=&gt;6379}, @redis_connection=#&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_5_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'map_5_xp'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#&quot;localhost&quot;, :port=&gt;6379}, @redis_connection=#&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_1_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_1'</span>, <span style="color:#006666;">10</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_1_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_2'</span>, <span style="color:#006666;">19</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_2_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_2'</span>, <span style="color:#006666;">7</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_3_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_3'</span>, <span style="color:#006666;">7</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_3_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_4'</span>, <span style="color:#006666;">17</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_4_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_4'</span>, <span style="color:#006666;">22</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_4_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_5'</span>, <span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_5_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_5'</span>, <span style="color:#006666;">3</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_1_xp_lb.<span style="color:#9900CC;">intersect_leaderboards</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'all_maps_xp_lb'</span>, <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'map_2_xp'</span>, <span style="color:#996600;">'map_3_xp'</span>, <span style="color:#996600;">'map_4_xp'</span>, <span style="color:#996600;">'map_5_xp'</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">0</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> all_maps_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'all_maps_xp_lb'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#&quot;localhost&quot;, :port=&gt;6379}, @redis_connection=#&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> all_maps_xp_lb.<span style="color:#9900CC;">total_members</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">0</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> all_maps_xp_lb.<span style="color:#9900CC;">leaders</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_2_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_1'</span>, <span style="color:#006666;">7</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_3_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_1'</span>, <span style="color:#006666;">8</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_4_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_1'</span>, <span style="color:#006666;">8</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_5_xp_lb.<span style="color:#9900CC;">add_member</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'member_1'</span>, <span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> map_1_xp_lb.<span style="color:#9900CC;">intersect_leaderboards</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'all_maps_xp_lb'</span>, <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'map_2_xp'</span>, <span style="color:#996600;">'map_3_xp'</span>, <span style="color:#996600;">'map_4_xp'</span>, <span style="color:#996600;">'map_5_xp'</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">1</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> all_maps_xp_lb = Leaderboard.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'all_maps_xp_lb'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#&quot;localhost&quot;, :port=&gt;6379}, @redis_connection=#&gt;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> all_maps_xp_lb.<span style="color:#9900CC;">total_members</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">1</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span> all_maps_xp_lb.<span style="color:#9900CC;">leaders</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#123;</span>:member<span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#996600;">&quot;member_1&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:score</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">35.0</span>, <span style="color:#ff3333; font-weight:bold;">:rank</span><span style="color:#006600; font-weight:bold;">=&gt;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
ruby<span style="color:#006600; font-weight:bold;">-</span>1.9.2<span style="color:#006600; font-weight:bold;">-</span>p0 <span style="color:#006600; font-weight:bold;">&gt;</span></pre></td></tr></table></div>

<p>Notice in our first intersection here of the leaderboards, no one member has played in all of the different maps, so we have an empty leaderboard. After a member has played in all of the maps, we now have a populated leaderboard.</p>
<p>The default behavior for the intersect leaderboards call is to sum the  scores for members present in any of the leaderboards. You could also  take a maximum or minimum score for members present in any of the  leaderboards to generate a high score (or low score) leaderboard across all of  the different maps.</p>
<p><strong>CAVEATS</strong></p>
<p>Latin? Seriously?</p>
<p>When you create a merged or intersected leaderboard, this new leaderboard does not track changes made to any of the leaderboards that were combined. If you want to update the merged or intersected leaderboard, you have to perform the merge or intersection again. As such, generating meta leaderboards is something you probably want to do at some regular interval, not after every score update. Just make sure your users know when the leaderboard is going to be updated.</p>
<p>Unlike my previous post on leaderboards, I didn&#8217;t run any performance metrics on the merge or intersection operations. I know I need to do that at some point and I will. So &#8230; stay tuned?</p>
<p><strong>FIN</strong></p>
<p>Meta leaderboards are nothing more than an aggregate leaderboard. I&#8217;ve shown merge and intersection operations that allow you to create different types of meta leaderboards. Meta leaderboards can be generated on a regular, but not too frequent basis so as not to tax your servers too bad.</p>
<p>You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">@CzarneckiD</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/03/02/meta-leaderboards/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How I Got Into The Video Game Industry</title>
		<link>http://www.altdevblogaday.com/2011/02/16/how-i-got-into-the-video-game-industry/</link>
		<comments>http://www.altdevblogaday.com/2011/02/16/how-i-got-into-the-video-game-industry/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 02:05:11 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
		
		<guid isPermaLink="false">http://altdevblogaday.org/?p=764</guid>
		<description><![CDATA[<p><strong>THE BEFORE TIME aka THE LONG, LONG AGO</strong></p>
<p>Before joining <a href="http://www.agoragames.com/">Agora Games</a> in May of 2008, I worked for a small company called General Electric for nearly 11 years in their Research and Development and Healthcare organizations. During that time, my interest in video games was re-kindled. I can remember the holiday shopping season when the slim PS2 was made available and OMFG I HAD TO HAVE ONE TO PLAY KATAMARI DAMACY! Thankfully I snagged one on Amazon.com and it was all downhill from there I guess. I got heavily into some now classics like God of War, God of War 2, Ico, Shadow of the Colossus, Okami and others. And then out of nowhere, I stumbled upon Dead Rising and OMFG I HAD TO BUY AN XBOX 360 TO KILL THE ZOMBIES. As it turns out, you could only reasonably play Dead Rising on an HDTV, so I attached that game onto a rocket ship and sent it flying into the sun (I still own Dead Rising, but have never completed it due to other issues that I will save for another blog post). I started playing the other XBOX 360 games that were all the rage at that time like the Halo series, Guitar Hero 2 and Guitar Hero 3, and others. However, I never really thought about joining the game industry even though there were 3 well-established video game companies here in upstate NY, <a href="http://www.vvisions.com/">Vicarious Visions</a>, <a href="http://1stplayable.com/">1st Playable</a>, and <a href="http://www.agoragames.com/">Agora Games</a> (even though I hadn&#8217;t known of Agora Games &#8230; yet).</p>
<p><a href="http://www.altdevblogaday.com/2011/02/16/how-i-got-into-the-video-game-industry/" class="more-link">Read more on How I Got Into The Video Game Industry&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><strong>THE BEFORE TIME aka THE LONG, LONG AGO</strong></p>
<p>Before joining <a href="http://www.agoragames.com/">Agora Games</a> in May of 2008, I worked for a small company called General Electric for nearly 11 years in their Research and Development and Healthcare organizations. During that time, my interest in video games was re-kindled. I can remember the holiday shopping season when the slim PS2 was made available and OMFG I HAD TO HAVE ONE TO PLAY KATAMARI DAMACY! Thankfully I snagged one on Amazon.com and it was all downhill from there I guess. I got heavily into some now classics like God of War, God of War 2, Ico, Shadow of the Colossus, Okami and others. And then out of nowhere, I stumbled upon Dead Rising and OMFG I HAD TO BUY AN XBOX 360 TO KILL THE ZOMBIES. As it turns out, you could only reasonably play Dead Rising on an HDTV, so I attached that game onto a rocket ship and sent it flying into the sun (I still own Dead Rising, but have never completed it due to other issues that I will save for another blog post). I started playing the other XBOX 360 games that were all the rage at that time like the Halo series, Guitar Hero 2 and Guitar Hero 3, and others. However, I never really thought about joining the game industry even though there were 3 well-established video game companies here in upstate NY, <a href="http://www.vvisions.com/">Vicarious Visions</a>, <a href="http://1stplayable.com/">1st Playable</a>, and <a href="http://www.agoragames.com/">Agora Games</a> (even though I hadn&#8217;t known of Agora Games &#8230; yet).</p>
<p><strong>CRAIGSLIST: GOOD FOR FINDING JOBS (winking smiley face)<br />
</strong></p>
<p>See what I did there? Get your mind out of the gutter! Anyhoo &#8230;</p>
<p>On the last project I was on at General Electric, I was working many long hours, many days of the week. A lot more than I ever wanted to. It wasn&#8217;t fun. At all. Life is too short to not do what you love. So, I started searching locally for a new job. I happened upon a job posting on Craigslist for a Software Engineer at Agora Games. I had no experience in the tools and frameworks outlined in the job posting, but I had been working in software professionally for nearly 15 years &#8230; and I loved video games &#8230; so that counts for something right? As it turns out, it does.</p>
<p>I submitted my resume on a Tuesday. I submitted a solution to a Pokemen traveling salesman problem (COLLECT THEM ALL) the following day. My first interview was the following Monday. Aside: In case you don&#8217;t know about Agora Games, one of the franchises we work with is Guitar Hero developing certain online and community functionality. So, here I am going into the interview thinking that not only am I going to be grilled technically, but I&#8217;ll probably have to demonstrate my skills playing <a href="http://www.youtube.com/watch?v=S5GpRJItqjw">&#8220;Through The Fire and Flames&#8221; on Expert</a>. My first interview went well. I didn&#8217;t have to demonstrate my Guitar Hero prowess, but I did have to explain how I would implement leaderboards to my now colleague, <a href="http://twitter.com/olamork">Ola Mork</a> (who&#8217;s laughing now Ola &#8211; see my other post on <a href="http://altdevblogaday.com/2011/01/31/leaderboards-a-how-to-guide/">Leaderboards: A How-To Guide</a>). I had a second lunch interview the following Monday with our CEO again and our new CTO. After lunch we went back to the studio, I had an offer, and I drove home and gave my 2 weeks notice to General Electric.</p>
<p><strong>GO OUT WITH A LITTLE PIZAZZ</strong></p>
<p>So, General Electric&#8217;s e-mail system has a Global Address List (GAL). At the time, General Electric owned NBC. I think they still have some stake in NBC, but whatever, not the point. The point is that almost all of NBC&#8217;s personalities like the entire cast of Saturday Night Live, the NBC Nightly News folks, Conan O&#8217; Brien (at the time still with NBC), Jay Leno, and more, all had e-mail addresses in the GAL. So, in my parting e-mail to all my colleagues at GE, I added every single celebrity I could think of. What did I care? I was leaving the company. At worst, they never read that e-mail. At best, I get a &#8220;Congratulations!&#8221; reply. As a fan of South Park, I ended my e-mail with the following:</p>
<blockquote><p>I will have to defer any “words of wisdom” to those of one Eric Cartman (yes &#8230; of South Park):</p>
<p>“Follow your dreams. You can reach your goals. I&#8217;m living proof. Beefcake. BEEFCAKE!”</p></blockquote>
<p>BOOM!</p>
<p><strong>TEQUILA ANYONE?<br />
</strong></p>
<p>If you can, line up your start date at your new company with an awesome &#8220;holiday&#8221;. I started at Agora Games on May 5th, 2008 aka Cinco de Mayo. I was joining the Guitar Hero team and we were working feverishly on updates for Guitar Hero: Aerosmith. On my first day I got to play Guitar Hero: World Tour (possibly unannounced at the time). Think hard about how you spent your first afternoon at your new job?</p>
<p><strong>FIN</strong></p>
<p>Joining the video game industry was and continues to be one of the best decisions I have ever made. Ever.</p>
<p>I realize the long and short of this blog post is that I got into the video game industry by applying for a job in the video game industry on Craigslist, but maybe that&#8217;s the point? If you want a job in the video game industry, apply for a job in the video game industry. Whether you&#8217;re a programmer or an artist or a musician or a writer or a player, there are jobs for any discipline.</p>
<p>So, apply.</p>
<p>Do it.</p>
<p>Now.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/02/16/how-i-got-into-the-video-game-industry/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Leaderboards: A How-To Guide</title>
		<link>http://www.altdevblogaday.com/2011/01/31/leaderboards-a-how-to-guide/</link>
		<comments>http://www.altdevblogaday.com/2011/01/31/leaderboards-a-how-to-guide/#comments</comments>
		<pubDate>Mon, 31 Jan 2011 15:00:00 +0000</pubDate>
		<dc:creator>David Czarnecki</dc:creator>
		
		<guid isPermaLink="false">http://altdevblogaday.org/2011/01/31/leaderboards-a-how-to-guide/</guid>
		<description><![CDATA[<p><span style="font-size: large;"><strong>INTRODUCTION</strong></span></p>
<p>Leaderboards in video games are an interesting beast. They are used to rank players against one another using some quantifiable criteria such as # of kills, XP, total time played, points in a level, etc. Leaderboards have been an intimate part of my life for almost 3 years now at Agora Games. As such, I&#8217;m always looking for ways to improve our leaderboard technology and answer questions like: How do you efficiently insert and rank players in real time? How do you efficiently update and re-rank players in real time? How do you retrieve information about a specific member of a leaderboard? How do you retrieve information about a player and players around them in a leaderboard?</p>
<p><a href="http://www.altdevblogaday.com/2011/01/31/leaderboards-a-how-to-guide/" class="more-link">Read more on Leaderboards: A How-To Guide&#8230;</a></p>
]]></description>
				<content:encoded><![CDATA[<p><span style="font-size: large;"><strong>INTRODUCTION</strong></span></p>
<p>Leaderboards in video games are an interesting beast. They are used to rank players against one another using some quantifiable criteria such as # of kills, XP, total time played, points in a level, etc. Leaderboards have been an intimate part of my life for almost 3 years now at Agora Games. As such, I&#8217;m always looking for ways to improve our leaderboard technology and answer questions like: How do you efficiently insert and rank players in real time? How do you efficiently update and re-rank players in real time? How do you retrieve information about a specific member of a leaderboard? How do you retrieve information about a player and players around them in a leaderboard?</p>
<p>It was the morning of January 1, 2011, <a href="http://twitter.com/CzarneckiD/status/21081627241226241">I had literally ridden the short bus</a> back from my New Year&#8217;s dinner some hours earlier, and I woke up with a desire to make the world more awesome. It&rsquo;s 2011 and we still don&rsquo;t have flying cars &hellip; so ,,|, future. Where to start? Leaderboards.</p>
<p><span style="font-size: large;"><strong>LEADERBOARDS USING REDIS</strong></span></p>
<p>At the studio I had discussed with colleagues the possibility of using <a href="http://redis.io/">Redis</a>, an advanced key-value storage engine, for leaderboards. In less than an hour, I had the set of Redis commands using their sorted set data type (a set of data that is sorted based on an associated &#8220;score&#8221;) to perform operations on leaderboards such as:</p>
<ul>
<li>Retrieving general information about a leaderboard such as total members or total pages</li>
<li>Adding or removing members from a leaderboard</li>
<li>Retrieving information about a member in the leaderboard such as their rank or score</li>
<li>Updating score information for a member in the leaderboard</li>
<li>Retrieving an arbitrary page of leaders from the leaderboard</li>
<li>Retrieving the leaders around a given member in a leaderboard, also known as an &ldquo;Around Me&rdquo; leaderboard</li>
<li>Retrieving information for an arbitrary set of members in a leaderboard, e.g. How do my friends compare against me?</li>
</ul>
<p>The result of all this is now encapsulated in the <a href="https://github.com/agoragames/leaderboard">leaderboard</a> gem (a Ruby library) that I open sourced on GitHub. There are <a href="http://redis.io/clients">Redis libraries in a number of programming languages</a> such as C, C# C++, Lua, etc. The leaderboard gem is merely a semantic wrapper around the underlying Redis commands. It is left as an exercise to the reader to port the leaderboard code to your favorite programming language.</p>
<p><span style="font-size: large;"><strong>RUBBER MEETS ROAD</strong></span></p>
<p>Here&#8217;s how you&#8217;d actually use the library to generate and interact with a &#8216;highscores&#8217; leaderboard as outlined above.</p>
<div class="data type-text">
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<pre class="line_numbers"><span rel="#L1" id="L1">1</span>
<span rel="#L2" id="L2">2</span>
<span rel="#L3" id="L3">3</span>
<span rel="#L4" id="L4">4</span>
<span rel="#L5" id="L5">5</span>
<span rel="#L6" id="L6">6</span>
<span rel="#L7" id="L7">7</span>
<span rel="#L8" id="L8">8</span>
<span rel="#L9" id="L9">9</span>
<span rel="#L10" id="L10">10</span>
<span rel="#L11" id="L11">11</span>
<span rel="#L12" id="L12">12</span>
<span rel="#L13" id="L13">13</span>
<span rel="#L14" id="L14">14</span>
<span rel="#L15" id="L15">15</span>
<span rel="#L16" id="L16">16</span>
<span rel="#L17" id="L17">17</span>
<span rel="#L18" id="L18">18</span>
<span rel="#L19" id="L19">19</span>
<span rel="#L20" id="L20">20</span>
<span rel="#L21" id="L21">21</span>
<span rel="#L22" id="L22">22</span>
<span rel="#L23" id="L23">23</span>
<span rel="#L24" id="L24">24</span>
<span rel="#L25" id="L25">25</span>
<span rel="#L26" id="L26">26</span>
<span rel="#L27" id="L27">27</span>
<span rel="#L28" id="L28">28</span>
<span rel="#L29" id="L29">29</span>
<span rel="#L30" id="L30">30</span>
<span rel="#L31" id="L31">31</span>
<span rel="#L32" id="L32">32</span>
<span rel="#L33" id="L33">33</span>
<span rel="#L34" id="L34">34</span>
<span rel="#L35" id="L35">35</span>
<span rel="#L36" id="L36">36</span>
<span rel="#L37" id="L37">37</span>
<span rel="#L38" id="L38">38</span>
<span rel="#L39" id="L39">39</span>
<span rel="#L40" id="L40">40</span>
<span rel="#L41" id="L41">41</span>
<span rel="#L42" id="L42">42</span>
<span rel="#L43" id="L43">43</span>
<span rel="#L44" id="L44">44</span>
<span rel="#L45" id="L45">45</span>
<span rel="#L46" id="L46">46</span>
<span rel="#L47" id="L47">47</span>
<span rel="#L48" id="L48">48</span>
<span rel="#L49" id="L49">49</span>
<span rel="#L50" id="L50">50</span>
<span rel="#L51" id="L51">51</span>
<span rel="#L52" id="L52">52</span>
<span rel="#L53" id="L53">53</span>
<span rel="#L54" id="L54">54</span>
<span rel="#L55" id="L55">55</span>
<span rel="#L56" id="L56">56</span>
<span rel="#L57" id="L57">57</span>
<span rel="#L58" id="L58">58</span>
<span rel="#L59" id="L59">59</span>
<span rel="#L60" id="L60">60</span>
<span rel="#L61" id="L61">61</span>
<span rel="#L62" id="L62">62</span>
<span rel="#L63" id="L63">63</span>
</pre>
</td>
<td width="100%">
<div class="highlight">
<pre /><div class="line" id="LC1">Create a new leaderboard or attach to an existing leaderboard named &#39;highscores&#39;:</div><div class="line" id="LC2"><br /></div><div class="line" id="LC3">&nbsp;&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb = Leaderboard.new(&#39;highscores&#39;)</div><div class="line" id="LC4">&nbsp;&nbsp;&nbsp;=&gt; #&lt;Leaderboard:0x1018e4250 @page_size=25, @port=6379, @host=&quot;localhost&quot;, @redis_connection=#&lt;Redis client v2.1.1 connected to redis://localhost:6379/0 (Redis v2.1.10)&gt;, @leaderboard_name=&quot;highscores&quot;&gt; </div><div class="line" id="LC5">&nbsp;&nbsp;&nbsp;</div><div class="line" id="LC6">If you need to pass in options for Redis, you can do this with the redis_options parameter:</div><div class="line" id="LC7"><br /></div><div class="line" id="LC8">&nbsp;&nbsp;redis_options = {:host =&gt; &#39;localhost&#39;, :port =&gt; 6379, :password =&gt; &#39;password&#39;, :db =&gt; &#39;some_redis_db&#39;}</div><div class="line" id="LC9">&nbsp;&nbsp;highscore_lb = Leaderboard.new(&#39;highscores&#39;, redis_options[:host], redis_options[:port], Leaderboard::DEFAULT_PAGE_SIZE, redis_options))</div><div class="line" id="LC10"><br /></div><div class="line" id="LC11">You can set the page size to something other than the default page size (25):</div><div class="line" id="LC12"><br /></div><div class="line" id="LC13">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.page_size = 5</div><div class="line" id="LC14">&nbsp;&nbsp;&nbsp;=&gt; 5 </div><div class="line" id="LC15">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb</div><div class="line" id="LC16">&nbsp;&nbsp;&nbsp;=&gt; #&lt;Leaderboard:0x1018e2130 @leaderboard_name=&quot;highscores&quot;, @page_size=5, @port=6379, @redis_connection=#&lt;Redis client v2.1.1 connected to redis://localhost:6379/0 (Redis v2.1.10)&gt;, @host=&quot;localhost&quot;, @redis_options={:host=&gt;&quot;localhost&quot;, :port=&gt;6379}&gt;   </div><div class="line" id="LC17">&nbsp;&nbsp;</div><div class="line" id="LC18">Add members to your leaderboard:</div><div class="line" id="LC19"><br /></div><div class="line" id="LC20">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; 1.upto(10) do |index|</div><div class="line" id="LC21">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;     highscore_lb.add_member(&quot;member_#{index}&quot;, index)</div><div class="line" id="LC22">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;  end</div><div class="line" id="LC23">&nbsp;&nbsp;&nbsp;=&gt; 1 </div><div class="line" id="LC24">&nbsp;&nbsp;</div><div class="line" id="LC25">Get some information about your leaderboard:</div><div class="line" id="LC26"><br /></div><div class="line" id="LC27">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.total_members</div><div class="line" id="LC28">&nbsp;&nbsp;&nbsp;=&gt; 10 </div><div class="line" id="LC29">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.total_pages</div><div class="line" id="LC30">&nbsp;&nbsp;&nbsp;=&gt; 1 </div><div class="line" id="LC31">&nbsp;&nbsp;</div><div class="line" id="LC32">Get some information about a specific member(s) in the leaderboard:</div><div class="line" id="LC33"><br /></div><div class="line" id="LC34">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.score_for(&#39;member_4&#39;)</div><div class="line" id="LC35">&nbsp;&nbsp;&nbsp;=&gt; 4.0 </div><div class="line" id="LC36">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.rank_for(&#39;member_4&#39;)</div><div class="line" id="LC37">&nbsp;&nbsp;&nbsp;=&gt; 7 </div><div class="line" id="LC38">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.rank_for(&#39;member_10&#39;)</div><div class="line" id="LC39">&nbsp;&nbsp;&nbsp;=&gt; 1 </div><div class="line" id="LC40">&nbsp;&nbsp;</div><div class="line" id="LC41">Get page 1 in the leaderboard:</div><div class="line" id="LC42"><br /></div><div class="line" id="LC43">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.leaders(1)</div><div class="line" id="LC44">	 =&gt; [{:member=&gt;&quot;member_10&quot;, :rank=&gt;1, :score=&gt;&quot;10&quot;}, {:member=&gt;&quot;member_9&quot;, :rank=&gt;2, :score=&gt;&quot;9&quot;}, {:member=&gt;&quot;member_8&quot;, :rank=&gt;3, :score=&gt;&quot;8&quot;}, {:member=&gt;&quot;member_7&quot;, :rank=&gt;4, :score=&gt;&quot;7&quot;}, {:member=&gt;&quot;member_6&quot;, :rank=&gt;5, :score=&gt;&quot;6&quot;}, {:member=&gt;&quot;member_5&quot;, :rank=&gt;6, :score=&gt;&quot;5&quot;}, {:member=&gt;&quot;member_4&quot;, :rank=&gt;7, :score=&gt;&quot;4&quot;}, {:member=&gt;&quot;member_3&quot;, :rank=&gt;8, :score=&gt;&quot;3&quot;}, {:member=&gt;&quot;member_2&quot;, :rank=&gt;9, :score=&gt;&quot;2&quot;}, {:member=&gt;&quot;member_1&quot;, :rank=&gt;10, :score=&gt;&quot;1&quot;}]</div><div class="line" id="LC45"><br /></div><div class="line" id="LC46">Add more members to your leaderboard:</div><div class="line" id="LC47"><br /></div><div class="line" id="LC48">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; 50.upto(95) do |index|</div><div class="line" id="LC49">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;     highscore_lb.add_member(&quot;member_#{index}&quot;, index)</div><div class="line" id="LC50">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;  end</div><div class="line" id="LC51">&nbsp;&nbsp;&nbsp;=&gt; 50 </div><div class="line" id="LC52">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.total_pages</div><div class="line" id="LC53">&nbsp;&nbsp;&nbsp;=&gt; 3 </div><div class="line" id="LC54">&nbsp;&nbsp;</div><div class="line" id="LC55">Get an &quot;Around Me&quot; leaderboard for a member:</div><div class="line" id="LC56"><br /></div><div class="line" id="LC57">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.around_me(&#39;member_53&#39;)</div><div class="line" id="LC58">	 =&gt; [{:member=&gt;&quot;member_65&quot;, :rank=&gt;31, :score=&gt;&quot;65&quot;}, {:member=&gt;&quot;member_64&quot;, :rank=&gt;32, :score=&gt;&quot;64&quot;}, {:member=&gt;&quot;member_63&quot;, :rank=&gt;33, :score=&gt;&quot;63&quot;}, {:member=&gt;&quot;member_62&quot;, :rank=&gt;34, :score=&gt;&quot;62&quot;}, {:member=&gt;&quot;member_61&quot;, :rank=&gt;35, :score=&gt;&quot;61&quot;}, {:member=&gt;&quot;member_60&quot;, :rank=&gt;36, :score=&gt;&quot;60&quot;}, {:member=&gt;&quot;member_59&quot;, :rank=&gt;37, :score=&gt;&quot;59&quot;}, {:member=&gt;&quot;member_58&quot;, :rank=&gt;38, :score=&gt;&quot;58&quot;}, {:member=&gt;&quot;member_57&quot;, :rank=&gt;39, :score=&gt;&quot;57&quot;}, {:member=&gt;&quot;member_56&quot;, :rank=&gt;40, :score=&gt;&quot;56&quot;}, {:member=&gt;&quot;member_55&quot;, :rank=&gt;41, :score=&gt;&quot;55&quot;}, {:member=&gt;&quot;member_54&quot;, :rank=&gt;42, :score=&gt;&quot;54&quot;}, {:member=&gt;&quot;member_53&quot;, :rank=&gt;43, :score=&gt;&quot;53&quot;}, {:member=&gt;&quot;member_52&quot;, :rank=&gt;44, :score=&gt;&quot;52&quot;}, {:member=&gt;&quot;member_51&quot;, :rank=&gt;45, :score=&gt;&quot;51&quot;}, {:member=&gt;&quot;member_50&quot;, :rank=&gt;46, :score=&gt;&quot;50&quot;}, {:member=&gt;&quot;member_10&quot;, :rank=&gt;47, :score=&gt;&quot;10&quot;}, {:member=&gt;&quot;member_9&quot;, :rank=&gt;48, :score=&gt;&quot;9&quot;}, {:member=&gt;&quot;member_8&quot;, :rank=&gt;49, :score=&gt;&quot;8&quot;}, {:member=&gt;&quot;member_7&quot;, :rank=&gt;50, :score=&gt;&quot;7&quot;}, {:member=&gt;&quot;member_6&quot;, :rank=&gt;51, :score=&gt;&quot;6&quot;}, {:member=&gt;&quot;member_5&quot;, :rank=&gt;52, :score=&gt;&quot;5&quot;}, {:member=&gt;&quot;member_4&quot;, :rank=&gt;53, :score=&gt;&quot;4&quot;}, {:member=&gt;&quot;member_3&quot;, :rank=&gt;54, :score=&gt;&quot;3&quot;}, {:member=&gt;&quot;member_2&quot;, :rank=&gt;55, :score=&gt;&quot;2&quot;}]	</div><div class="line" id="LC59"><br /></div><div class="line" id="LC60">Get rank and score for an arbitrary list of members (e.g. friends):</div><div class="line" id="LC61"><br /></div><div class="line" id="LC62">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; highscore_lb.ranked_in_list([&#39;member_1&#39;, &#39;member_62&#39;, &#39;member_67&#39;], true)</div><div class="line" id="LC63">&nbsp;&nbsp;&nbsp;=&gt; [{:rank=&gt;55, :member=&gt;&quot;member_1&quot;, :score=&gt;1.0}, {:rank=&gt;33, :member=&gt;&quot;member_62&quot;, :score=&gt;62.0}, {:rank=&gt;28, :member=&gt;&quot;member_67&quot;, :score=&gt;67.0}]   </div></pre>
</div>
</td>
</tr>
</table></div>
</p>
<p>Let&#8217;s cover a few more scenarios in-depth as to what calls you might make.</p>
<p>I&#8217;ve based Scenario 1 and 2 from LittleBigPlanet. NOTE: I have absolutely no idea if this is what actually happens in that game.</p>
<p><strong>Scenario 1</strong>: Player finishes a level in game, upload player&#8217;s score (add_member), display to the player the scores around them (set page_size and use around_me call for player).</p>
<div class="data type-text">
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<pre class="line_numbers"><span rel="#L1" id="L1">1</span>
<span rel="#L2" id="L2">2</span>
<span rel="#L3" id="L3">3</span>
<span rel="#L4" id="L4">4</span>
<span rel="#L5" id="L5">5</span>
<span rel="#L6" id="L6">6</span>
<span rel="#L7" id="L7">7</span>
<span rel="#L8" id="L8">8</span>
<span rel="#L9" id="L9">9</span>
<span rel="#L10" id="L10">10</span>
<span rel="#L11" id="L11">11</span>
<span rel="#L12" id="L12">12</span>
<span rel="#L13" id="L13">13</span>
<span rel="#L14" id="L14">14</span>
<span rel="#L15" id="L15">15</span>
<span rel="#L16" id="L16">16</span>
<span rel="#L17" id="L17">17</span>
<span rel="#L18" id="L18">18</span>
<span rel="#L19" id="L19">19</span>
</pre>
</td>
<td width="100%">
<div class="highlight">
<pre /><div class="line" id="LC1">fossil:leaderboard dczarnecki$ irb</div><div class="line" id="LC2">ruby-1.8.7-p302 &gt; require &#39;rubygems&#39;</div><div class="line" id="LC3">&nbsp;=&gt; true </div><div class="line" id="LC4">ruby-1.8.7-p302 &gt; require &#39;leaderboard&#39;</div><div class="line" id="LC5">&nbsp;=&gt; true </div><div class="line" id="LC6">ruby-1.8.7-p302 &gt; highscore_lb = Leaderboard.new(&#39;highscores&#39;)</div><div class="line" id="LC7">&nbsp;=&gt; #&lt;Leaderboard:0x1011b23b0 @leaderboard_name=&quot;highscores&quot;, @page_size=25, @port=6379, @redis_connection=#&lt;Redis client v2.1.1 connected to redis://localhost:6379/0 (Redis v2.0.4)&gt;, @host=&quot;localhost&quot;, @redis_options={:host=&gt;&quot;localhost&quot;, :port=&gt;6379}&gt; </div><div class="line" id="LC8">ruby-1.8.7-p302 &gt; 1.upto(10) do |index|</div><div class="line" id="LC9">ruby-1.8.7-p302 &gt;     highscore_lb.add_member(&quot;member_#{index}&quot;, index)</div><div class="line" id="LC10">ruby-1.8.7-p302 ?&gt;  end</div><div class="line" id="LC11">&nbsp;=&gt; 1 </div><div class="line" id="LC12">ruby-1.8.7-p302 &gt; highscore_lb.add_member(&#39;DavidCzarnecki&#39;, 6)</div><div class="line" id="LC13">&nbsp;=&gt; true </div><div class="line" id="LC14">ruby-1.8.7-p302 &gt; highscore_lb.page_size = 5</div><div class="line" id="LC15">&nbsp;=&gt; 5 </div><div class="line" id="LC16">ruby-1.8.7-p302 &gt; highscore_lb.around_me(&#39;DavidCzarnecki&#39;)</div><div class="line" id="LC17">&nbsp;=&gt; [{:member=&gt;&quot;member_7&quot;, :score=&gt;&quot;7&quot;, :rank=&gt;4}, {:member=&gt;&quot;member_6&quot;, :score=&gt;&quot;6&quot;, :rank=&gt;5}, {:member=&gt;&quot;DavidCzarnecki&quot;, :score=&gt;&quot;6&quot;, :rank=&gt;6}, {:member=&gt;&quot;member_5&quot;, :score=&gt;&quot;5&quot;, :rank=&gt;7}, {:member=&gt;&quot;member_4&quot;, :score=&gt;&quot;4&quot;, :rank=&gt;8}] </div><div class="line" id="LC18">ruby-1.8.7-p302 &gt; </div><div class="line" id="LC19"><br /></div></pre>
</div>
</td>
</tr>
</table></div>
</p>
<p><strong>Scenario 2</strong>: Player finishes same level in game, update player&#8217;s score (add_member), display to the player the scores around them (set page_size and use around_me call for player). Note, you can call add_member again, because under the hood in Redis, it will just update the player&#8217;s score (if it exists) and re-rank.</p>
<div class="data type-text">
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<pre class="line_numbers"><span rel="#L1" id="L1">1</span>
<span rel="#L2" id="L2">2</span>
<span rel="#L3" id="L3">3</span>
<span rel="#L4" id="L4">4</span>
<span rel="#L5" id="L5">5</span>
<span rel="#L6" id="L6">6</span>
<span rel="#L7" id="L7">7</span>
<span rel="#L8" id="L8">8</span>
</pre>
</td>
<td width="100%">
<div class="highlight">
<pre /><div class="line" id="LC1">ruby-1.8.7-p302 &gt; highscore_lb.add_member(&#39;DavidCzarnecki&#39;, 15)</div><div class="line" id="LC2">&nbsp;=&gt; false </div><div class="line" id="LC3">ruby-1.8.7-p302 &gt; highscore_lb.page_size = 5</div><div class="line" id="LC4">&nbsp;=&gt; 5 </div><div class="line" id="LC5">ruby-1.8.7-p302 &gt; highscore_lb.around_me(&#39;DavidCzarnecki&#39;)</div><div class="line" id="LC6">&nbsp;=&gt; [{:member=&gt;&quot;DavidCzarnecki&quot;, :score=&gt;&quot;15&quot;, :rank=&gt;1}, {:member=&gt;&quot;member_10&quot;, :score=&gt;&quot;10&quot;, :rank=&gt;2}, {:member=&gt;&quot;member_9&quot;, :score=&gt;&quot;9&quot;, :rank=&gt;3}, {:member=&gt;&quot;member_8&quot;, :score=&gt;&quot;8&quot;, :rank=&gt;4}, {:member=&gt;&quot;member_7&quot;, :score=&gt;&quot;7&quot;, :rank=&gt;5}] </div><div class="line" id="LC7">ruby-1.8.7-p302 &gt; </div><div class="line" id="LC8"><br /></div></pre>
</div>
</td>
</tr>
</table></div>
</p>
<p>I&#8217;ve based Scenario 3 and 4 from Call of Duty: Black Ops playing a wager match. NOTE: I have absolutely no idea if this is what actually happens in that game. Also, in Scenario 3 and 4, you could certainly use the add_member call with the player&#8217;s total earnings. I simply want to illustrate the delta call (change_score_for).</p>
<p><strong>Scenario 3</strong>: Players finish a match and you want to update their winnings (change_score_for) for that match.</p>
<div class="data type-text">
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<pre class="line_numbers"><span rel="#L1" id="L1">1</span>
<span rel="#L2" id="L2">2</span>
<span rel="#L3" id="L3">3</span>
<span rel="#L4" id="L4">4</span>
<span rel="#L5" id="L5">5</span>
<span rel="#L6" id="L6">6</span>
<span rel="#L7" id="L7">7</span>
<span rel="#L8" id="L8">8</span>
<span rel="#L9" id="L9">9</span>
<span rel="#L10" id="L10">10</span>
</pre>
</td>
<td width="100%">
<div class="highlight">
<pre /><div class="line" id="LC1">ruby-1.8.7-p302 &gt; total_money_lb = Leaderboard.new(&#39;total_money&#39;)</div><div class="line" id="LC2">&nbsp;=&gt; #&lt;Leaderboard:0x101180680 @leaderboard_name=&quot;total_money&quot;, @page_size=25, @port=6379, @redis_connection=#&lt;Redis client v2.1.1 connected to redis://localhost:6379/0 (Redis v2.0.4)&gt;, @host=&quot;localhost&quot;, @redis_options={:host=&gt;&quot;localhost&quot;, :port=&gt;6379}&gt; </div><div class="line" id="LC3">ruby-1.8.7-p302 &gt; total_money_lb.change_score_for(&#39;DavidCzarnecki&#39;, 15)</div><div class="line" id="LC4">&nbsp;=&gt; &quot;15&quot; </div><div class="line" id="LC5">ruby-1.8.7-p302 &gt; total_money_lb.change_score_for(&#39;ChristianArca&#39;, 7)</div><div class="line" id="LC6">&nbsp;=&gt; &quot;7&quot; </div><div class="line" id="LC7">ruby-1.8.7-p302 &gt; total_money_lb.leaders(1)</div><div class="line" id="LC8">&nbsp;=&gt; [{:member=&gt;&quot;DavidCzarnecki&quot;, :score=&gt;&quot;15&quot;, :rank=&gt;1}, {:member=&gt;&quot;ChristianArca&quot;, :score=&gt;&quot;7&quot;, :rank=&gt;2}] </div><div class="line" id="LC9">ruby-1.8.7-p302 &gt; </div><div class="line" id="LC10"><br /></div></pre>
</div>
</td>
</tr>
</table></div>
</p>
<p><strong>Scenario 4</strong>: Players finish another wager match and you want to update their winnings (change_score_for) for that match. NOTE: If you use negative values, the score is decremented.</p>
<div class="data type-text">
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<pre class="line_numbers"><span rel="#L1" id="L1">1</span>
<span rel="#L2" id="L2">2</span>
<span rel="#L3" id="L3">3</span>
<span rel="#L4" id="L4">4</span>
<span rel="#L5" id="L5">5</span>
<span rel="#L6" id="L6">6</span>
<span rel="#L7" id="L7">7</span>
<span rel="#L8" id="L8">8</span>
</pre>
</td>
<td width="100%">
<div class="highlight">
<pre /><div class="line" id="LC1">ruby-1.8.7-p302 &gt; total_money_lb.change_score_for(&#39;DavidCzarnecki&#39;, -8)</div><div class="line" id="LC2">&nbsp;=&gt; &quot;7&quot; </div><div class="line" id="LC3">ruby-1.8.7-p302 &gt; total_money_lb.change_score_for(&#39;ChristianArca&#39;, 16)</div><div class="line" id="LC4">&nbsp;=&gt; &quot;23&quot; </div><div class="line" id="LC5">ruby-1.8.7-p302 &gt; total_money_lb.leaders(1)</div><div class="line" id="LC6">&nbsp;=&gt; [{:member=&gt;&quot;ChristianArca&quot;, :score=&gt;&quot;23&quot;, :rank=&gt;1}, {:member=&gt;&quot;DavidCzarnecki&quot;, :score=&gt;&quot;7&quot;, :rank=&gt;2}] </div><div class="line" id="LC7">ruby-1.8.7-p302 &gt; </div><div class="line" id="LC8"><br /></div></pre>
</div>
</td>
</tr>
</table></div>
</p>
<p><span style="font-size: large;"><strong>BUT &#8230; REDIS?</strong></span></p>
<p>It&#8217;s <a href="http://redis.io/topics/benchmarks">fast</a> because data lives in-memory. It&#8217;s <a href="http://redis.io/topics/persistence">durable</a> because you can configure it to write to disk. It&#8217;s <a href="http://redis.io/topics/replication">scaleable</a> because you can setup master-slave replication to have multiple read-only slaves. I assume all of these are important to you as game developers.</p>
<p>All of this amounts to a Guarantee Fairy right? It makes a man feel good. You figure you put this blog post under your pillow at night, the Guarantee Fairy might come by and leave a quarter, am I right? What&#8217;s my point? The point is, how do you know the fairy isn&#8217;t a crazy glue sniffer?  &#8220;Building model airplanes&#8221; says the little fairy; well, we&#8217;re not buying  it. He sneaks into your house once, that&#8217;s all it takes. The next thing  you know, there&#8217;s money missing off the dresser, and your daughter&#8217;s  knocked up. I&#8217;ve seen it a hundred times.</p>
<p>Wait &#8230; <a href="http://www.imdb.com/title/tt0114694/">what</a>?</p>
<p><span style="font-size: large;"><strong>SCIENCE. IT WORKS B*TCHES</strong></span></p>
<p>One of the things I love about Redis is that it&#8217;s backed by science &#8230; mathematics and computer science. In particular, all of the commands give their respective time complexity in <a href="http://en.wikipedia.org/wiki/Big_o_notation">Big O notation</a>. If you don&#8217;t know what that is, consider yourself fired. Not really. But &#8230; still. It&#8217;s important because you want to know how long operations are going to take given a particular data set size. This might be useful information from a game developer&#8217;s perspective to figure out average or worst-case scenario time estimates for interacting with a leaderboard based on total expected players.</p>
<p>At the request of one of my colleagues, <a href="http://twitter.com/olamork">Ola Mork</a>, I did some basic benchmarking. Insert 10 million sequential scores into a leaderboard (in practice you will probably not be doing this all at once) and determine the average time to request an arbirtrary page from the leaderboard. Insert 10 million random scores into a leaderboard (again, in practice you will probably not be doing this all at once) and determine the average time to request an arbitary page from the leaderboard.</p>
<p>The long and short of it is that it&#8217;s fast. Negligible difference in terms of leaderboard page retrieval.</p>
<div class="data type-text">
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<pre class="line_numbers"><span rel="#L1" id="L1">1</span>
<span rel="#L2" id="L2">2</span>
<span rel="#L3" id="L3">3</span>
<span rel="#L4" id="L4">4</span>
<span rel="#L5" id="L5">5</span>
<span rel="#L6" id="L6">6</span>
<span rel="#L7" id="L7">7</span>
<span rel="#L8" id="L8">8</span>
<span rel="#L9" id="L9">9</span>
<span rel="#L10" id="L10">10</span>
<span rel="#L11" id="L11">11</span>
<span rel="#L12" id="L12">12</span>
<span rel="#L13" id="L13">13</span>
<span rel="#L14" id="L14">14</span>
<span rel="#L15" id="L15">15</span>
<span rel="#L16" id="L16">16</span>
<span rel="#L17" id="L17">17</span>
<span rel="#L18" id="L18">18</span>
<span rel="#L19" id="L19">19</span>
<span rel="#L20" id="L20">20</span>
<span rel="#L21" id="L21">21</span>
<span rel="#L22" id="L22">22</span>
<span rel="#L23" id="L23">23</span>
<span rel="#L24" id="L24">24</span>
<span rel="#L25" id="L25">25</span>
<span rel="#L26" id="L26">26</span>
<span rel="#L27" id="L27">27</span>
<span rel="#L28" id="L28">28</span>
<span rel="#L29" id="L29">29</span>
<span rel="#L30" id="L30">30</span>
<span rel="#L31" id="L31">31</span>
<span rel="#L32" id="L32">32</span>
<span rel="#L33" id="L33">33</span>
<span rel="#L34" id="L34">34</span>
<span rel="#L35" id="L35">35</span>
<span rel="#L36" id="L36">36</span>
<span rel="#L37" id="L37">37</span>
<span rel="#L38" id="L38">38</span>
<span rel="#L39" id="L39">39</span>
<span rel="#L40" id="L40">40</span>
<span rel="#L41" id="L41">41</span>
<span rel="#L42" id="L42">42</span>
<span rel="#L43" id="L43">43</span>
<span rel="#L44" id="L44">44</span>
<span rel="#L45" id="L45">45</span>
<span rel="#L46" id="L46">46</span>
<span rel="#L47" id="L47">47</span>
<span rel="#L48" id="L48">48</span>
<span rel="#L49" id="L49">49</span>
<span rel="#L50" id="L50">50</span>
<span rel="#L51" id="L51">51</span>
<span rel="#L52" id="L52">52</span>
</pre>
</td>
<td width="100%">
<div class="highlight">
<pre /><div class="line" id="LC1">10 million sequential scores insert:</div><div class="line" id="LC2"><br /></div><div class="line" id="LC3">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; insert_time = Benchmark.measure do</div><div class="line" id="LC4">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;       1.upto(10000000) do |index|</div><div class="line" id="LC5">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;           highscore_lb.add_member(&quot;member_#{index}&quot;, index)</div><div class="line" id="LC6">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;      end</div><div class="line" id="LC7">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;  end</div><div class="line" id="LC8">&nbsp;&nbsp;&nbsp;=&gt; #&lt;Benchmark::Tms:0x101605660 @label=&quot;&quot;, @stime=173.61, @total=577.52, @real=911.718175172806, @utime=403.91, @cstime=0.0, @cutime=0.0&gt; </div><div class="line" id="LC9">&nbsp;&nbsp;</div><div class="line" id="LC10">Average time to request an arbitrary page from the leaderboard:</div><div class="line" id="LC11"><br /></div><div class="line" id="LC12">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; requests_to_make = 50000</div><div class="line" id="LC13">&nbsp;&nbsp;&nbsp;=&gt; 50000 </div><div class="line" id="LC14">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; lb_request_time = 0</div><div class="line" id="LC15">&nbsp;&nbsp;&nbsp;=&gt; 0 </div><div class="line" id="LC16">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; 1.upto(requests_to_make) do</div><div class="line" id="LC17">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;       lb_request_time += Benchmark.measure do</div><div class="line" id="LC18">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;           highscore_lb.leaders(rand(highscore_lb.total_pages))</div><div class="line" id="LC19">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;      end.total</div><div class="line" id="LC20">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;  end</div><div class="line" id="LC21">&nbsp;&nbsp;&nbsp;=&gt; 1 </div><div class="line" id="LC22">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; </div><div class="line" id="LC23">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;   p lb_request_time / requests_to_make</div><div class="line" id="LC24">&nbsp;&nbsp;0.001808</div><div class="line" id="LC25">&nbsp;&nbsp;&nbsp;=&gt; nil </div><div class="line" id="LC26">&nbsp;&nbsp;</div><div class="line" id="LC27">10 million random scores insert:</div><div class="line" id="LC28"><br /></div><div class="line" id="LC29">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; insert_time = Benchmark.measure do</div><div class="line" id="LC30">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;       1.upto(10000000) do |index|</div><div class="line" id="LC31">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;           highscore_lb.add_member(&quot;member_#{index}&quot;, rand(50000000))</div><div class="line" id="LC32">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;      end</div><div class="line" id="LC33">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;  end</div><div class="line" id="LC34">&nbsp;&nbsp;&nbsp;=&gt; #&lt;Benchmark::Tms:0x10164ebf8 @label=&quot;&quot;, @stime=172.94, @total=577.91, @real=1356.57155895233, @utime=404.97, @cstime=0.0, @cutime=0.0&gt; </div><div class="line" id="LC35">&nbsp;&nbsp;</div><div class="line" id="LC36">Average time to request an arbitrary page from the leaderboard:</div><div class="line" id="LC37"><br /></div><div class="line" id="LC38">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; requests_to_make = 50000</div><div class="line" id="LC39">&nbsp;&nbsp;&nbsp;=&gt; 50000 </div><div class="line" id="LC40">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; lb_request_time = 0</div><div class="line" id="LC41">&nbsp;&nbsp;&nbsp;=&gt; 0 </div><div class="line" id="LC42">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; 1.upto(requests_to_make) do</div><div class="line" id="LC43">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;       lb_request_time += Benchmark.measure do</div><div class="line" id="LC44">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;           highscore_lb.leaders(rand(highscore_lb.total_pages))</div><div class="line" id="LC45">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;      end.total</div><div class="line" id="LC46">&nbsp;&nbsp;ruby-1.8.7-p302 ?&gt;  end</div><div class="line" id="LC47">&nbsp;&nbsp;&nbsp;=&gt; 1 </div><div class="line" id="LC48">&nbsp;&nbsp;ruby-1.8.7-p302 &gt; </div><div class="line" id="LC49">&nbsp;&nbsp;ruby-1.8.7-p302 &gt;   p lb_request_time / requests_to_make</div><div class="line" id="LC50">&nbsp;&nbsp;0.00179680000000001</div><div class="line" id="LC51">&nbsp;&nbsp;&nbsp;=&gt; nil </div><div class="line" id="LC52"><br /></div></pre>
</div>
</td>
</tr>
</table></div>
</p>
<p><strong><span style="font-size: large;">FIN</span></strong></p>
<p>Leaderboards may seem complicated, but they are not. Wrapping software like Redis with a set of semantic commands, we have a near complete set of use cases covered for how we might interact with a leaderboard. Finally, it&#8217;s fast.</p>
<p>Take a look at the <a href="https://github.com/agoragames/leaderboard">leaderboard</a> gem code and get involved. Comments or code. The choice is yours.</p>
<p>You can find more hilarity over on my Twitter account, <a href="http://twitter.com/czarneckid">CzarneckiD</a>.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.altdevblogaday.com/2011/01/31/leaderboards-a-how-to-guide/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
