tag:blogger.com,1999:blog-61406321385696895102024-03-05T22:37:10.217-08:00missingbytesmissingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.comBlogger60125tag:blogger.com,1999:blog-6140632138569689510.post-4569477401256563422020-02-23T21:24:00.000-08:002020-06-10T19:19:55.702-07:00The Cacophony IndexCan we estimate the health of an ecosystem from a digital audio recording?<br />
<div style="text-align: right;">
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-small;">(Part 2 in a series about Artificial Intelligence and New Zealand native birds.)</span></div>
<div class="separator" style="clear: both; text-align: center;">
<span id="goog_2073662635"></span><span id="goog_2073662636"></span><br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='160' height='133' src='https://www.blogger.com/video.g?token=AD6v5dxR8laZk2CtLsPWgC6NVYDYnk8wxNW6u22atHLMj6-U627Vhmyh2aze9rHVbsgdiekEPhZ2bKVn3Ru-3O54yg' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
Inside a computer, 20 seconds of audio are represented by a sequence of 320,000 numbers.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWwuAzGdEQuwpsQSCpwFO6WplXPp_HwF90DurqkEE6jETX-HNb9IuGN3GM5oHx6IMpKthdta7CiYAK4cXsoAtgYpwLSCLEASUJhVjrNg9YVx1WRhGlVnSBz3LH2OsgCHKQqaRa8JPyj14/s1600/waveform.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="256" data-original-width="1282" height="78" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWwuAzGdEQuwpsQSCpwFO6WplXPp_HwF90DurqkEE6jETX-HNb9IuGN3GM5oHx6IMpKthdta7CiYAK4cXsoAtgYpwLSCLEASUJhVjrNg9YVx1WRhGlVnSBz3LH2OsgCHKQqaRa8JPyj14/s400/waveform.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">20 seconds of audio, plotted as a waveform</td></tr>
</tbody></table>
Our challenge is to take that series of 320,000 numbers and extract one single number, a "Cacophony Index", that has some special properties:<br />
<ul>
<li>Birds nearby and birds far away increase the Index about the same.</li>
<li>Background noises don't affect the Index very much.</li>
<li>The Cacophony Index for two sparrows chirping should be higher than if there's only one.</li>
<li>The Cacophony Index for a sparrow chirping and an owl hooting should be higher than for two sparrows chirping.</li>
</ul>
<br />
Wow, that’s a really hard thing to do! As happens often in this blog, we'll make the problem easier by adding in some assumptions:<br />
<div style="border: 2px solid black; float: right; margin: 1em; padding: 1em; width: 30%;">
<span style="font-size: x-small;"> <a href="https://en.wikipedia.org/wiki/Perfect_is_the_enemy_of_good">"Perfect is the enemy of good"</a> - Voltaire</span><br />
<span style="font-size: x-small;"><span style="font-size: xx-small;"><br />
</span> <span style="font-size: xx-small;">Are we justified in making all these assumptions?</span></span><br />
<span style="font-size: x-small;"> ...Well, no...</span><br />
<div style="text-align: center;">
<span style="font-size: x-small;">...but... </span></div>
<div style="text-align: right;">
<span style="font-size: x-small;">... let's do it anyway.</span></div>
<span style="font-size: x-small;"><span style="font-size: xx-small;"><br />
</span> <span style="font-size: xx-small;"> Lets build something useful instead of freaking out that a perfect solution can't exist.<br />
<br />
<i>That means we're going to just ignore a whole bunch of nasty complications like “clipping”, “nyquist rate”, “attenuation”, “noise floor”, etc</i></span></span><br />
<br />
Because PROGRESS!</div>
<ul>
<li>Most of the loud noises in the recordings are birds, not people or cars or machines.</li>
<li>The recording is “clean”</li>
<li>The birds and the recorder stay in the same place.</li>
<li>No running water or ocean waves (!)</li>
<li>The recording was taken in New Zealand (!!)</li>
</ul>
<br />
<br />
Great stuff! Lets look at the <a href="https://en.wikipedia.org/wiki/Spectrogram">spectrogram</a>: <style type="text/css">
@page { margin: 2cm }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { so-language: zxx }
</style> <br />
<div style="line-height: 100%; margin-bottom: 0cm;">
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmTcFFyZ0TpiD0GYbMAwcW_pL1MhvYe8DXCK2yZpeBm1NHBb82jqhF6zEaxgySntUTumo0Boj38nj83rNuXqx-ikwVSamxRD367g1A1XWyAAwdTCbaIB9oRtp0WgNoas03FZFgHU7w6Y4/s1600/spectrogram.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="80" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmTcFFyZ0TpiD0GYbMAwcW_pL1MhvYe8DXCK2yZpeBm1NHBb82jqhF6zEaxgySntUTumo0Boj38nj83rNuXqx-ikwVSamxRD367g1A1XWyAAwdTCbaIB9oRtp0WgNoas03FZFgHU7w6Y4/s400/spectrogram.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><style type="text/css">
@page { margin: 2cm }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { so-language: zxx }
</style> <br />
<div style="line-height: 100%; margin-bottom: 0.21cm; margin-top: 0.21cm;">
<span style="font-size: 12pt;"><i>The </i></span><i style="font-size: 16px;"><a href="https://en.wikipedia.org/wiki/Spectrogram">spectrogram</a></i><i style="font-size: 12pt;"> is a visual representation of the spectrum of frequencies of a signal as it varies with time. </i></div>
</td></tr>
</tbody></table>
<style type="text/css">
@page { margin: 2cm }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { so-language: zxx }
</style> <br />
<div style="line-height: 100%; margin-bottom: 0cm;">
We don’t care so much about the intensity of any given bird call, that mostly tells us how near or far the bird is.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br />
We don’t care so much if the bird has a short call or a long call.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br />
Background noise? That’s where the spectrogram is well.. noisy..</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
</div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3KHxiKFz5GshLnLHVg92g8JVTm7m2tsD1UAH-AauZ2deFWX8Pl4dvoyKH5w_AVTn9neqO6xVDptwD87d6bQ8_TQKywziAaphhmXd3uTn5f5g7Xw6cVXqlaYI1i_2Nb11M6Qrb9Z23lZo/s1600/Merge.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3KHxiKFz5GshLnLHVg92g8JVTm7m2tsD1UAH-AauZ2deFWX8Pl4dvoyKH5w_AVTn9neqO6xVDptwD87d6bQ8_TQKywziAaphhmXd3uTn5f5g7Xw6cVXqlaYI1i_2Nb11M6Qrb9Z23lZo/s320/Merge.png" width="299" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="text-align: start;"><span style="font-size: xx-small;">Count the number of times a yellow box is next to a blue box!<br />
That's the heart of the Cacophony Index calculation.</span></span></td></tr>
</tbody></table>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br />
What we’re really looking for is how the spectrogram changes over time.<br />
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Lets zoom in on that starting second and add a grid to isolate the signal in both time and frequency:</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
</div>
</div>
<div style="line-height: 19.2px;">
<br />
A little bit more math and we find the cacophony index for this particular audio recording is: <span style="font-size: x-large;">77</span></div>
<div style="line-height: 19.2px;">
</div>
<br />
OK, you got me, I'm oversimplifying again! <span style="background-color: white; color: #545454; font-family: "arial" , sans-serif; font-size: 14px;">¯\_(ツ)\_/¯ </span>If you want all the gory details, <a href="https://github.com/TheCacophonyProject/audio-analysis/blob/master/Melt/cacophony_index.py">the code is on github.com</a> <br />
<div style="line-height: 100%; margin-bottom: 0cm;">
</div>
<br />
<br />
<h4>
Lets talk Birds!</h4>
The Cacophony Index for 20 seconds of audio is just a number between zero and one hundred. By itself, not super useful.<br />
<br />
If we make many recordings in the same location, we can plot how the Cacophony Index changes over time. Here's one possible presentation of what that might look like over the course of a day: <br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyXrGbwGMQ9B7-sluW2S97GyEmVxpDFtEPyZA9RuZNZkOnjcaiAD-y7v1FnPVBgeZEgODRFQmKI-XX-gFAZ_DyCQLRP04_jgGZoYKdwLZ02n3oLmVvJmNRsLqHtuPB1d-TtmbAKv8r1z0/s1600/ui.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyXrGbwGMQ9B7-sluW2S97GyEmVxpDFtEPyZA9RuZNZkOnjcaiAD-y7v1FnPVBgeZEgODRFQmKI-XX-gFAZ_DyCQLRP04_jgGZoYKdwLZ02n3oLmVvJmNRsLqHtuPB1d-TtmbAKv8r1z0/s400/ui.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: small; text-align: start;">You can clearly see the birds are more active during the day and less active during the night. The birds getting really noisy around sunrise and sunset, the "Dawn Chorus".</span></td></tr>
</tbody></table>
<br />
Even though the plot is a mock-up, the data is real. It's data from a real bird monitor, recorded near Christchurch, New Zealand over a three week period in November of 2019. We now have the technology to see how the Cacophony Index changes over a day, or a week, or even seasons, years or decades.<br />
<br />
And that's exactly what the <a href="https://cacophony.org.nz/cacophony-index-live">Cacophony Project</a> are doing, using real audio recorded right here in New Zealand, uploaded continuously and automatically by people just like you! (<a href="https://www.2040.co.nz/blogs/news/cacophony-index-back-processing-now-complete">Edit: Live! Check it out!</a>)<br />
<br />
I think that's awesome. Can we go deeper?<br />
<br />
Now we have an automated way to track an ecosystem's health, what else can we do with the audio data?<style type="text/css">
@page { margin: 2cm }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { so-language: zxx }
</style> <br />
<br />
<div style="text-align: right;">
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: x-small;">Watch this space for an update using real AI using Tensorflow and some real world ethical problems.</span></div>
<style type="text/css">
@page { margin: 2cm }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { so-language: zxx }
</style>missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com2tag:blogger.com,1999:blog-6140632138569689510.post-22046309502267904782020-01-30T18:55:00.000-08:002020-06-10T19:20:09.657-07:00Engineering in the Native Forest<div style="text-align: right;">
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: xx-small;">Part 1 in a 2 part series about Artificial Intelligence and New Zealand native birds.</span></div>
<br />
We’ve all heard that sound, and it is glorious. Native birds singing in pristine native forest.<br />
<a href="https://commons.wikimedia.org/wiki/File:NZ_Southern_Island_forest.jpg" title="Satoru Kikuchi [CC BY 2.0 (https://creativecommons.org/licenses/by/2.0)], via Wikimedia Commons"><img alt="NZ Southern Island forest" src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/NZ_Southern_Island_forest.jpg/512px-NZ_Southern_Island_forest.jpg" width="512" /></a><br />
<br />
Then tragedy happens. It could be an introduced pest like possums or rats. Maybe the climate changes and the native birds cannot adapt. Maybe it’s just a really really really bad year for bird flu.<br />
<br />
The once vibrant healthy forest falls quiet. The native bird population is in crisis. <br />
<br />
Meanwhile, over on social media:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkYnIu6d-WHVzaZYZwndvMXPZhaT_blSuKb02Gz8xAE2DF4DSfZLl8fW4PfWrMp7hijNgL-uibhFitrO-fN3_admv1bBhYHxXI4rwd8Wn611VdoL29uBQNCIKbCAnLrjifhTK79oKFNn4/s1600/CapObv.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="556" data-original-width="1200" height="148" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkYnIu6d-WHVzaZYZwndvMXPZhaT_blSuKb02Gz8xAE2DF4DSfZLl8fW4PfWrMp7hijNgL-uibhFitrO-fN3_admv1bBhYHxXI4rwd8Wn611VdoL29uBQNCIKbCAnLrjifhTK79oKFNn4/s320/CapObv.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXfdW6xAPQ-kSVu0zjQxNCPwxuTIi4hbJmCl5o6AWhp6cr4vSFBl40MmwIBT2iAKVa6saqKf9UpLsyANcT3gaxTxJ4h8ssU-xBi9E69G92ooalvGfdpgR2grAMPoI8lwxDNnO1l27ffUU/s1600/BuldWall.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="556" data-original-width="1200" height="148" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXfdW6xAPQ-kSVu0zjQxNCPwxuTIi4hbJmCl5o6AWhp6cr4vSFBl40MmwIBT2iAKVa6saqKf9UpLsyANcT3gaxTxJ4h8ssU-xBi9E69G92ooalvGfdpgR2grAMPoI8lwxDNnO1l27ffUU/s320/BuldWall.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAGxqRPlsWIMp2ZjFrQJo2j3eFZ12QqULEqDsLy48AXwryURzcQcdqaDRuLHMEPqMlpEpNcayEdZQCH29_VbK1gFHyrP3_KT-JX3QhqSlt9511Gyu4yiPCcBCRmv0mg8CRU3lL2YemgTs/s1600/7nJiDo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="622" data-original-width="1600" height="124" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAGxqRPlsWIMp2ZjFrQJo2j3eFZ12QqULEqDsLy48AXwryURzcQcdqaDRuLHMEPqMlpEpNcayEdZQCH29_VbK1gFHyrP3_KT-JX3QhqSlt9511Gyu4yiPCcBCRmv0mg8CRU3lL2YemgTs/s320/7nJiDo.png" width="320" /></a></div>
<br />
I think it’s awesome when people are passionate about their local environment. I think it’s amazing when folks break out of their comfort zone and try to bring about positive change.<span id="goog_1086217589"></span><br />
<br />
We all know that blindly doing the first thing that pops into your head is rarely the best course of action. Even with the best of intentions, when it comes to the environment, there’s just far too many ways to make the situation worse.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid-hsqPCRXBVnF4nb13Eo98yfRo0oQYc7oCdIvlT_KgJShgjDnDRcUw7WZTb1KUQrseDgf5P6ipszXQ9lAxcLTa-Omwq7oZIj58P1HdLrLfWj8BzlrG9_9bqHMzTvxYIWPm5crdpJIClM/s1600/Science.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuFPQhTtX7iHnqRIcPo61YSUK5q9YRrcgLtmjz2HV7eo8x8I2Ex9-1uERM0LfExCsbcR7izbZkAzKC4NY6tbZIc92iqn9uxshx9d8JbDV0vCHFFeIBUcXJJrQhcvZVPShfXZB5wG9KpF0/s1600/Intervention.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuFPQhTtX7iHnqRIcPo61YSUK5q9YRrcgLtmjz2HV7eo8x8I2Ex9-1uERM0LfExCsbcR7izbZkAzKC4NY6tbZIc92iqn9uxshx9d8JbDV0vCHFFeIBUcXJJrQhcvZVPShfXZB5wG9KpF0/s320/Intervention.png" width="320" /></a></div>
Fortunately, we can use Engineering!<br />
<br />
<ul>
<li>First, we measure the health of an ecosystem.<br /><br />
</li>
<li>Next, we apply an intervention:<br />
<ul>
<li>pest trapping</li>
<li>a breeding program</li>
<li>fences</li>
<li>[Your idea here]</li>
</ul>
</li>
<li>Then, we measure the health of the ecosystem a second time.</li>
</ul>
<br />
Mix in a little bit of math, and now we can figure out which interventions are the most effective.<br />
<br />
Those interventions which are more (cost) effective? We'll do more of those.<br />
<br />
The interventions which have no effect, or worse, are damaging? Well, let's not do that again!<br />
<br />
<div style="text-align: center;">
<span style="font-size: large;">Simple right?</span></div>
<div style="text-align: center;">
<br /></div>
Well how do we measure ecosystem health?<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Y2WCqZqtnTIhag2oeSv4KXKCPCDmQXwH6SgVhJ2YmELF215hZLQVA1AJ-p8bIQCfKJ7WZYrHp16j0U4rK14lzYl9UMr-Uq9vARYQjGUR9VSUIvXbpqjKSGJdc4J6_kfMPni_BrALqB8/s1600/kereru.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="988" data-original-width="988" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Y2WCqZqtnTIhag2oeSv4KXKCPCDmQXwH6SgVhJ2YmELF215hZLQVA1AJ-p8bIQCfKJ7WZYrHp16j0U4rK14lzYl9UMr-Uq9vARYQjGUR9VSUIvXbpqjKSGJdc4J6_kfMPni_BrALqB8/s200/kereru.jpg" width="200" /></a>Right now, in New Zealand, the gold standard is a manual process. Listeners walk out into the forest, and for five minutes, makes a record of all the birds they can hear on a piece of paper. Those pieces of paper are all brought together and another person manually enters all that data into a computer.<br />
<br />
What if there was a way to estimate ecosystem health directly from an audio stream instead? Then we could leave recorders out in the forest, and monitor them remotely. More data, more timely, more consistency.<br />
<br />
I'm good with computers and signal processing and things, <span style="font-size: large;">maybe I can help...</span><br />
<br />
<div style="text-align: right;">
<span style="font-family: "arial" , "helvetica" , sans-serif; font-size: xx-small;">Find out more over on the <a href="https://www.2040.co.nz/blogs/news/you-can-now-see-your-cacophony-index">2040 blog</a>, or <a href="http://missingbytes.blogspot.com/2020/02/the-cacophony-index.html">read Part 2</a></span></div>
missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-20407829230161698742019-10-18T19:35:00.001-07:002019-10-19T02:38:04.324-07:00ShiftPBuddy of mine wants to straighten some images automatically, kinda like <a href="http://www.shiftn.de/">ShiftN</a> :<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuF3EMUlv7AYfyFf0r4f8ELKOhO3LvE4a6BJ11d_96Rt1OowUqzsHnvLZZz0lVZAwUBsp2dNureLUzxF1BlS4v38lhs74kTaJM02Gt4wS-nfKLQsrfEXWZ1hxCqrmkxpefcGfitDXiLls/s1600/fix.jpg" imageanchor="1"><img border="0" height="444" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuF3EMUlv7AYfyFf0r4f8ELKOhO3LvE4a6BJ11d_96Rt1OowUqzsHnvLZZz0lVZAwUBsp2dNureLUzxF1BlS4v38lhs74kTaJM02Gt4wS-nfKLQsrfEXWZ1hxCqrmkxpefcGfitDXiLls/s640/fix.jpg" width="640" /></a><br />
<br />
<br />
Oh, you'll want Python version 2, I said:<br />
<div style="border: 1px solid; margin: 10px;">
<span style="font-family: "courier new" , "courier" , monospace;">#makefile</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">PIP2=pip</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">PYTHON2=python</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;">setup2:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>$(PIP2) install --user virtualenv</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>$(PYTHON2) -m virtualenv v2</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>source v2/bin/activate && pip install numpy Pillow pylsd</span></div>
<div>
<br /></div>
And Python 3, I said, also in a <b>VirtualENVironment</b> sandbox:<br />
<div style="border: 1px solid; margin: 10px;">
<span style="font-family: "courier new" , "courier" , monospace;">#makefile</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">PIP3=pip3</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">PYTHON3=python3</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;">setup3:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>#$(PYTHON3) -m <b>venv</b> v3</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>source v3/bin/activate && pip install numpy Pillow scipy</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;">setup: setup2 setup3</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>-mkdir temp<br />
</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">run:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>source v2/bin/activate && python FindLines.py Source.jpg</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>source v3/bin/activate && python Warp.py</span><br />
<div>
<br /></div>
</div>
Start by finding all your lines:<br />
<div style="border: 1px solid; margin: 10px;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKbaIA4VsCDJpwRrX637UTowBTwokJXmrMNpKAtPdJHiT5TUDOIX1k13A8CzFSN8oUNECDkY99-XYN1btUulG3WwOMqI0lC-YGjHuPejv9zleIT21iqmma5syUV7f7B9UXEynvuXMNJzg/s1600/CheckLines.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKbaIA4VsCDJpwRrX637UTowBTwokJXmrMNpKAtPdJHiT5TUDOIX1k13A8CzFSN8oUNECDkY99-XYN1btUulG3WwOMqI0lC-YGjHuPejv9zleIT21iqmma5syUV7f7B9UXEynvuXMNJzg/s320/CheckLines.png" width="240" /></a><span style="font-family: "courier new" , "courier" , monospace;">#FindLines.py</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">import json</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">import numpy</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">import sys</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;">from PIL import Image</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">import pylsd.lsd</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;">def ExportMeta(fileName,outName):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>meta={'fileName':fileName}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>image=Image.open(fileName)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>meta['width']=image.width</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>meta['height']=image.height</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>grayScale=numpy.asarray(image.convert('L'))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>lines=pylsd.lsd(grayScale)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>lineArray=[]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>for row in lines:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>lineArray.append(list(row))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>meta['lineArray']=lineArray</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>with open(outName,'w') as f:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>f.write(json.dumps(meta,sort_keys=True,separators=(',', ': '),indent=4))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ExportMeta(sys.argv[1],'temp/meta.json')</span></div>
Always prefilter your inputs, I nagged:<br />
<div style="border: 1px solid; margin: 10px;">
<span style="font-family: "courier new" , "courier" , monospace;">#Warp.py</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">def FindWeightedLines(lineArray,meta):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>linesHorizontal=[]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>linesVertical=[]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>for (x0,y0,x1,y1,width) in lineArray:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if width<2:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>continue</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>h0=RemapXY(x0,y0,meta)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>h1=RemapXY(x1,y1,meta)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dx=abs(h0[0]-h1[0])</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dy=abs(h0[1]-h1[1])</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if max(dx,dy)<min(dx,dy)*4:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>continue</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>magnitude=dx*dx+dy*dy</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if dx<dy:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>linesHorizontal.append([magnitude,h0,h1])</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>else:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>linesVertical.append([magnitude,h0,h1])</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>return sorted(linesHorizontal)[-30:]+sorted(linesVertical)[-30:]<br />
#Always prefilter your inputs!!!</span></div>
<br />
Now here's the tricksy bit, in *TWO* parts, setup a perspective transform:<br />
<div style="border: 1px solid; margin: 10px;">
<span style="font-family: "courier new" , "courier" , monospace;">#Warp.py</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">def RemapXY(x,y,meta):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>xx=(x-meta['width']/2)/meta['scale']</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>yy=(y-meta['height']/2)/meta['scale']</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>return (xx,yy,1)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;">def UnmapXYZ(xx,yy,zz,meta):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>rx=xx/zz</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>ry=yy/zz</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>x=rx*meta['scale']+meta['width']/2</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>y=ry*meta['scale']+meta['height']/2</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>return (x,y)</span></div>
<div>
<br /></div>
*And* a non-linear warp. We don't need the full power of <a href="https://en.wikipedia.org/wiki/Chebyshev_polynomials">Chebyshev Polynomials</a> here, I reminded him. We can just use <span style="font-family: "verdana" , sans-serif;">0, 1, x, y, x<sup>2</sup>, y<sup>2</sup></span> and <span style="font-family: "verdana" , sans-serif;">xy</span>. Why? Because all spanning basis-es are equivalent in low dimensions!<br />
<div style="border: 1px solid; margin: 10px;">
<span style="font-family: "courier new" , "courier" , monospace;">#Warp.py</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">def ApplyTransform(transform,x,y,z):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>rx=x*transform[0]+y*transform[1]+z*transform[2]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>ry=x*transform[3]+y*transform[4]+z*transform[5]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>rz=x*transform[6]+y*transform[7]+z*transform[8]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>nonLinear=True</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if nonLinear:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>rx+=x*y*transform[9]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>ry+=x*y*transform[10]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>rx+=x*x*transform[11]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>ry+=x*x*transform[12]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>rx+=y*y*transform[13]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>ry+=y*y*transform[14]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>return (rx,ry,rz)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;">def ApplyTransformhomogenous(transform,x,y,z):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>(hx,hy,hz)=ApplyTransform(transform,x,y,z)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>return (hx/hz,hy/hz)</span></div>
<div>
<br />
Next you'll need a loss function, weakly constrain your transform matrix, then setup a sum-of-squares for your error term:<br />
<div style="border: 1px solid; margin: 10px; text-indent: 0px;">
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;">#Warp.py<br />def loss(transform,meta):</span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span><span style="font-family: "courier new" , "courier" , monospace;">result=0</span></span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>for i in range(9):</span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>t=transform[i]</span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if i==0 or i == 4 or i == 8:</span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>t=transform[i]-1</span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>result += t*t</span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>for(weight,h0,h1) in meta['weightedLineArray']:</span></span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>(x2,y2)=ApplyTransformHomogenous(transform,*h0)</span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>(x3,y3)=ApplyTransformHomogenous(transform,*h1)</span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dx=abs(x3-x2)</span></div>
<div style="color: black; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dy=abs(y3-y2)</span></div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if dx<dy:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>(dx,dy)=(dy,dx)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>q=math.sqrt(dx*dx + dy*dy)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dx=dx/q</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dy=dy/q</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;"></span><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>result += dy*dy</span><br />
<div style="color: black; font-family: times; font-size: medium; font-style: normal; font-weight: 400; letter-spacing: normal; text-transform: none; white-space: normal; word-spacing: 0px;">
<br /></div>
</div>
Are we done yet? Oh, a driver...:<br />
<div style="border: 1px solid; margin: 10px;">
<span style="font-family: "courier new" , "courier" , monospace;">#Warp.py<br />def Main():</span><br />
<span style="font-family: "courier new" , "courier" , monospace; white-space: pre;"> </span><span style="font-family: "courier new" , "courier" , monospace;">with open('temp/meta.json','r') as f:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>meta=json.loads(f.read())</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>meta['scale']=math.sqrt(meta['width']*meta['height'])/2</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; white-space: pre;"> </span><span style="font-family: "courier new" , "courier" , monospace;">meta['weightedLineArray']=FindWeightedLines(meta['lineArray'],meta)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>m=minimize(loss,[1,0,0,0,1,0,0,0,1,0,0,0,0,0,0],args=meta)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>transform=m.x</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>(x0,y0,x1,y1) = FindClipRectangle(...)</span><br />
<div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>source=Image.open(</span><span style="font-family: "courier new" , "courier" , monospace;">meta['fileName']</span><span style="font-family: "courier new" , "courier" , monospace;">)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; white-space: pre;"> </span><span style="font-family: "courier new" , "courier" , monospace;">image=Image.new('RGB',(x1-x0,y1-y0),(0,0,0))</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>draw=ImageDraw.Draw(image)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>meta['splitCount']=64</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>for x in range(meta['splitCount']):</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>for y in range(meta['splitCount']):</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>p00=SquareMap(x,y,meta)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>p01=SquareMap(x,y+1,meta)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>p10=SquareMap(x+1,y,meta)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>p11=SquareMap(x+1,y+1,meta)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>r00=ApplyTransform(transform,*RemapXY(*p00,meta))</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>r01=ApplyTransform(transform,*RemapXY(*p01,meta))</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>r10=ApplyTransform(transform,*RemapXY(*p10,meta))</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>r11=ApplyTransform(transform,*RemapXY(*p11,meta))</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>s00=UnmapXYZ(*r00,meta)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>s01=UnmapXYZ(*r01,meta)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>s10=UnmapXYZ(*r10,meta)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>s11=UnmapXYZ(*r11,meta)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>TextureMapTriangle(draw,x0,y0,x1,y1,source,s00,s01,s10,p00,p01,p10)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>TextureMapTriangle(draw,x0,y0,x1,y1,source,s10,s01,s11,p10,p01,p11)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>print('Progress %d/%d'%(x,meta['splitCount']),flush=True)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>image.save('temp/warped.jpg')</span></div>
</div>
</div>
</div>
<div>
<br /></div>
<div>
Oh, and you need texture mapped triangles? Python is terrible for that, there's no way to make it run fast.... Fine, here's one of those, just to get you started, but don't blame me if it's slow, this needs to be in OpenGL or something so you can run it on the GPU and apply proper gamma correction.<br />
<br />
<div style="border: 1px solid; margin: 10px;">
<span style="font-family: "courier new" , "courier" , monospace;">#TextureMapTriangle.py</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">def Left(p,a,b):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>cross=(p[0]-a[0])*(b[1]-a[1])-(p[1]-a[1])*(b[0]-a[0])</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>return cross<0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;">def SampleMap(source,x,y,dx,dy):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if x<0:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>x=0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if y<0:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>y=0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if x>=source.width:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>x=source.width-1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if y>=source.height:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>y=source.height-1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>return source.getpixel((x,y))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;">def TextureMapTriangle(draw,x0,y0,x1,y1,source,p0,p1,p2,uv0,uv1,uv2):</span><br />
<span style="font-family: "courier new" , "courier" , monospace; white-space: pre;"> </span><span style="font-family: "courier new" , "courier" , monospace;">xy0=list(map(min,zip(p0,p1,p2)))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>xy1=list(map(max,zip(p0,p1,p2)))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dx1=p1[0]-p0[0]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dy1=p1[1]-p0[1]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dx2=p2[0]-p0[0]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dy2=p2[1]-p0[1]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>det=dx1*dy2-dx2*dy1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if xy0[0]<x0:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>xy0[0]=x0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if xy0[1]<y0:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>xy0[1]=y0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if xy1[0]>x1:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>xy1[0]=x1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if xy1[1]>y1:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>xy1[1]=y1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>for x in range(math.floor(xy0[0]),math.ceil(xy1[0])):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>for y in range(math.floor(xy0[1]),math.ceil(xy1[1])):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>p=(x,y)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; white-space: pre;"> </span><span style="font-family: "courier new" , "courier" , monospace;">if Left(p,p0,p1):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>continue</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if Left(p,p1,p2):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>continue</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>if Left(p,p2,p0):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>continue</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dx=x-p0[0]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>dy=y-p0[1]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>u=(dx*dy2-dy*dx2)/det</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>v=(-dx*dy1+dy*dx1)/det</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span> <span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>uu=uv0[0]+u*(uv1[0]-uv0[0])+v*(uv2[0]-uv0[0])</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>vv=uv0[1]+u*(uv1[1]-uv0[1])+v*(uv2[1]-uv0[1])</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="white-space: pre;"> </span>c=SampleMap(source,uu,vv,1,1)</span><br />
<span style="font-family: "courier new" , "courier" , monospace; white-space: pre;"> </span><span style="font-family: "courier new" , "courier" , monospace;">draw.point((x-x0,y-y0),tuple(c))</span></div>
<div>
<br /></div>
</div>
<div>
<br /></div>
And then you could be like me, and license all of the above code under <a href="https://creativecommons.org/share-your-work/public-domain/cc0/">CC0</a>. Yay!missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-9447838309720051592018-05-10T23:53:00.000-07:002018-05-11T00:00:54.220-07:00Duplex<br />
Duplex. That’s the technology at Google I/O 2018 where an AI agent can use the existing telephone network to call a restaurant, book a table for 4 at 7pm, and adapt to common problems.<br />
<br />
Things get more interesting when the restaurant runs a similar service. AI talking to AI.<br />
<br />
Whenever two learning AI’s get together, every single time, they develop a new language. One that us humans can’t understand.<br />
<br />
I can imagine the following “conversation”: Alice, a digital assistant, is calling Bob, an AI agent for the restaurant.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> Alice and Bob together: Hi</span><br />
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"> Alice: Umm, er, hmmm, yes?</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"><br />
Bob: Table confirmed, 4 people, tonight at 7pm.<br />
<br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"> Alice and Bob together: Bye</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Lets slow that recording down and play it back again, annotated this time:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> Alice and Bob together: Hi</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: inherit;"> Handshake protocol, are we both digital software? Yes we are.</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"> Alice: Umm, er, hmmm, yes?</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: inherit;"> Translation: I’d like to book a table for 4 people anytime between 6pm and 9pm</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"> Bob: Table confirmed, 4 people, tonight at 7pm.</span><br />
<span style="font-family: inherit;"> Lets repeat everything for the recording the humans will review.</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: "courier new" , "courier" , monospace;"> Alice and Bob together: Bye</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: inherit;"> Handshake protocol, confirm booking.</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br />
<br />
Are there new words the AI can teach us? More efficient grammatical structures? Can the AI teach us humans to communicate more effectively?<br />
<br />
If there is, the AI won’t tell us.<br />
<br />
Unless we know how to ask.</div>
missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-32446811460214238612017-04-14T21:40:00.000-07:002018-05-11T00:05:47.664-07:00Basic Income, Better Living Through Video Games.If we assume as given we'll eventually live in a society with a UBI (all eligible citizens receive an Unconditional Basic Income, enough to cover their food, clothing and shelter), then the most pressing question is: <i>How should we roll it out?</i><br />
<br />
Years of making Video Games suggest two quick answers:<br />
<br />
The easy way is by lottery. Suppose Gary is a winner in the monthly UBI Lottery! Congrats Gary! Gary no longer has to deal with our mess of confusing taxation and welfare regulations. He wins a much simplified UBI and a flat tax. Of course, any change can be scary and difficult, so Gary also has the option to just stick with the old system if he wants.<br />
<br />
More interesting is the notion of a Dual Currency. It's a little bit like enrolling in the food stamp program, where he's issued with tokens that can be exchanged for food items at a 1-1 ratio. In a food stamp program, those tokens would normally expire after a set period of time.<br />
<br />
Food stamps are really old. Like, 1930's America old. We live in a digital world, so lets make those tokens work more like an energy mechanic in Candy Crush or League of Legends. Those tokens now accrue *continuously* rather than appearing all at once on a Thursday. We'll cap Gary's balance at a maximum of 1 months worth of tokens. Any balance more than 2 weeks of tokens would also have a penalty applied.<br />
<br />
Finally pricing. Staples like bread, milk, laundry detergent and cleaning supplies will have a heavily discounted price when purchased using tokens. Healthy options like fruit and vegetables too. Fast food and chocolates might have a premium pricing attached. Lets make it easier for Gary to make good decisions.<br />
<br />
<br />missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com1tag:blogger.com,1999:blog-6140632138569689510.post-66763775829645380422016-11-11T13:18:00.000-08:002016-11-12T03:24:23.587-08:00Brexit, Elections, and population in 2016Define: “effective political unit”<br />
<br />
If politics is the name we give to a group of people making decisions that affect all the members of that group, then we can use “effective political unit” (EPU) as a catch-all name to reference that group.<br />
<br />
Your household is an EPU. Your local sports team is an EPU. Your neighborhood and your city are both EPUs, as is your country, and each of your online communities.<br />
<br />
We can get a rough feel for the relative size of an EPU by adding the search term "population" and hitting the "I'm feeling lucky" button on google:<br />
<div style="text-align: center;">
<br /></div>
<table border="1" style="text-align: center;"><tbody>
<tr> <td>EPU</td><td>Size (million people)</td> </tr>
<tr><td>UK</td><td>65</td></tr>
<tr><td>California</td><td>35</td></tr>
<tr><td>Scotland</td><td>5</td></tr>
<tr><td>Quebec</td><td>8</td></tr>
<tr><td>London (England)</td><td>8</td></tr>
<tr><td>London (Ontario)</td><td>0.5</td></tr>
<tr><td>You</td><td>0.000001</td></tr>
<tr><td>Me</td><td>0.000001</td></tr>
<tr><td>You & Me together</td><td>0.000002</td></tr>
<tr><td>USA</td><td>320</td></tr>
<tr><td>North America (*)</td><td>580</td></tr>
<tr><td>Singapore</td><td>6</td></tr>
<tr><td>OECD (*)</td><td>560</td></tr>
<tr><td>China</td><td>1350</td></tr>
<tr><td>Eve Online</td><td>0.4</td></tr>
<tr><td>Alberta</td><td>4</td></tr>
<tr><td>New Zealand</td><td>4</td></tr>
<tr><td>Islam</td><td>1600</td></tr>
<tr><td>World</td><td>7500</td></tr>
<tr><td>Tokyo</td><td>14</td></tr>
</tbody></table>
<div style="text-align: center;">
<br /></div>
(*) The OECD includes all of North America, so as with any "I'm feeling lucky" google search, the error bars are large.<br />
<br />
A natural question to ask: "Given each Effective Political Unit is a group of people making decisions, what size of EPU is the most successful?" It's hard to pick an exact number, but like many trends associated with people, it's increasing over time, and the rate of increase is increasing:<br />
<br />
<br />
<table border="1" style="text-align: center;"><tbody>
<tr> <td>EPU</td><td>Size (million people)</td><td>Year</td> </tr>
<tr><td>Toba Catastrophe</td><td>0.07</td><td>70,000 BCE</td></tr>
<tr><td>Nomadic tribe</td><td>0.001</td><td>prehistory</td></tr>
<tr><td>Ancient Greece</td><td>5</td><td>400 BCE</td></tr>
<tr><td>Ptolemaic Egypt</td><td>7</td><td>300 BCE</td></tr>
<tr><td>Han dynasty</td><td>57</td><td>2 CE</td></tr>
<tr><td>Ancient Rome (peak)</td><td>60</td><td>160 CE</td></tr>
<tr><td>Mayan city</td><td>0.1</td><td>700 CE</td></tr>
<tr><td>Walmart Employees</td><td>2</td><td>2015 CE</td></tr>
</tbody></table>
<br />
<br />
<h3>
2016</h3>
<br />
A vote for a <a href="https://en.wikipedia.org/wiki/Protectionism">protectionist</a> like #Trump favors smaller (USA, 320) over #Clinton's larger (World, 7500).<br />
<br />
A #brexit vote favors smaller (UK, 65) over #remain's larger (EU, 500).<br />
<br />
A #califrexit (California, 35) is even smaller still.<br />
<br />
Which brings us back to the core question of this blogpost: What size of EPU is the most successful?<br />
<br />
Historically, every EPU has had a maximum size, once it extends past that point, it is doomed to collapse. At the same time, history is filled with EPUs that were too small, and were out-competed by slightly larger EPUs which were more effective.<br />
<br />
<br />
It's a classic value judgement.<br />
<div>
<br />
<br />
As social animals, we weigh the perceived risks and benefits between larger EPUs and smaller EPUs, and make a call, then find a post-hoc rationalization for our decision.<br />
<br /></div>
<br />
What I find fascinating is the schism between younger voters and older voters. If you look into the various exit polls around the world, a clear trend starts to emerge: Older voters seem to be favoring the 10MM-50MM range, while younger voters seem to be consistently voting in support of larger and larger EPUs.<br />
<br />
What does it all mean? At the risk of rampant speculation, do younger voters have more confidence in technology to enable larger and larger EPUs? Do older voters have more hands on experience with large EPUs getting out of control and collapsing? I really have nothing to back up either of those statements, but it sure is fun to make sweeping generalizations :D<br />
<br />
Let me know your thoughts in the comments down below!missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com1tag:blogger.com,1999:blog-6140632138569689510.post-13429786919731203762016-10-09T22:13:00.000-07:002016-10-09T22:13:03.706-07:00Cheapest 3D PrinterMy latest obsession is trying to build a 3D printer for as cheap as possible.<br />
<br />
Partly it's because I believe 3D printing is a disruptive technology. The lower the cost for making a 3D printer, the more people will have access to the technology, and sooner the disruption will take place.<br />
<br />
And partly, it's because I'm just really really cheap.<br />
<h3>
<br /></h3>
<h3>
Low Cost</h3>
What does low cost really mean? One obvious way is to look at the price of something if we were to buy it new in a shop. If we only source new parts and new materials, we're going to have a difficult time creating something truly low cost.<br />
<br />
My strategy is different. I'm going to try and get as many of the source materials as possible for "zero dollars."<br />
<br />
Consider old car tyres. Any time you can recycle the rubber from an old car tyre into a seesaw or a swing, or into building materials or to protect a wharf, then the cost of that rubber is effectively "zero dollars."<br />
<br />
That's why the core design elements of my 3D printer are going to be fishing line and lego. Two very cheap substances if you source them the right way.<br />
<br />
<h3>
Fishing Line</h3>
Nylon fishing line is an amazing substance. It's strong. Durable. Inexpensive. It's readily available everywhere around the globe. And if you need small quantities, you can often obtain it for "zero dollars". You probably already have some.<br />
<br />
<h3>
Lego</h3>
Lego is an amazing substance. It's available everywhere. It's manufactured to extremely high tolerances. It's consistent across time and place. It comes in a variety of colors. It's durable.<br />
While lego might not be cheap, you can often *borrow* lego for "zero dollars" by using the magic words "I'm trying to make a 3D printer out of lego."<br />
Once your print run is complete, you can simply disassemble the lego and return it to it's previous state.<br />
<br />
<h3>
Calibration Problem</h3>
When I look at the designs for existing 3D printers, one of the biggest design considerations seems to be finding out where the extrusion point is in relation to the "bed". Existing designs carefully measure the motion of the motors, try really hard to make the frame rigid, and then have lots of complicated software to try and calculate where exactly the filament is being deposited.<br />
<br />
Ack, too difficult.<br />
<br />
Why go through all the calculation, when you can measure directly?<br />
<br />
My plan is to use the <b>camera</b> on an <b>Android tablet</b> to see where the bed is, and, at the same time, to see where the print head is. If it needs to move to the left, well, the tablet will keep the motors spinning until it lines up. Too far to the right? no problem, spin the motors the other way until it matches. Checkmate calibration problem!<br />
<br />
<h3>
OpenCV</h3>
<br />
Oh, and remember our lego? We know exactly how large a block is in the real world, so we can measure off distance in our 2D camera space by placing a known lego calibration object made with a few different known colors.<br />
<br />
This way it doesn't matter if our fishing line stretches during the course of the print, or our lego gets bumped half way through, or the ambient temperature changes which make the layers a tiny bit thinner.. no problem, the camera on the android tablet sees all.<br />
<br />
And how much does it cost for an Android tablet? "zero dollars." You just have to use the magic words: "Can I borrow your Android tablet to make a 3D printer?"<br />
<br />
<h3>
Next Steps</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg55yd7tKGYAo649NyHIgJBhjgf3Bs6OKnoiVqbssOFwlLQH0xN0vY_wZxDPmAkO2qM8yruTAz465c-4j6-51Z7-0RmfJEmgQh0MJ9bvncWRAahcsoNRWtqsely5zJnew4uQ98OZG_mM94/s1600/3DPrinter.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg55yd7tKGYAo649NyHIgJBhjgf3Bs6OKnoiVqbssOFwlLQH0xN0vY_wZxDPmAkO2qM8yruTAz465c-4j6-51Z7-0RmfJEmgQh0MJ9bvncWRAahcsoNRWtqsely5zJnew4uQ98OZG_mM94/s400/3DPrinter.jpg" width="400" /></a>I've already starting on version 1 of the prototype. Watch this space.missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com3tag:blogger.com,1999:blog-6140632138569689510.post-7307451396796866682016-10-01T16:47:00.000-07:002016-10-01T17:54:44.264-07:00ELI5: What are the differences between the C programming languages: C, C++, C#, and Objective C?<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHVijTJ6e5OqXSJhlSktzNNuCrTCWDHI29jmLlvixFNzWnR3WZW8lraHrbNXSQlGIFKkmFu0vAwwJ5ppEaucjG2LFu-XrCDWnh2KfbdRNX3fiwI63R0QGPz-nbK5AjZfdfXH3AwY50Hgk/s1600/C.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHVijTJ6e5OqXSJhlSktzNNuCrTCWDHI29jmLlvixFNzWnR3WZW8lraHrbNXSQlGIFKkmFu0vAwwJ5ppEaucjG2LFu-XrCDWnh2KfbdRNX3fiwI63R0QGPz-nbK5AjZfdfXH3AwY50Hgk/s1600/C.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">"Hello World" in C</td></tr>
</tbody></table>
C, C++, C# and Objective-C are all programming languages. They're all special ways of writing where a programmer can ask a computer to solve problems for the programmer.<br />
<br />
Don't be fooled by the letter “C” in their names, the 4 languages are actually quite different.<br />
<br />
<hr />
<br />
<b>C</b> is the oldest of the 4. It was one of the first really popular programming languages because it was good at solving the types of problems that programmers had way back in the 1980's. Things like “portability”, “memory management” and “correctness”.<br />
<br />
C is quite a simple language, which means you need to do a lot of writing to ask the computer to do complicated things.<br />
<br />
<hr />
<br />
<b>C++</b> is actually C with lots and lots of extra stuff added in. It's name is a pun, where to the computer, C++ means something like “better than C”. And yeah, there's other computer languages with pun names like “D” and “F#” too. Because C++ is a lot more powerful than C, you don't need to write quite so much stuff to get the computer to do complicated things.<br />
<br />
<hr />
<br />
<b>Objective-C</b> is also C but with different stuff added into it. Both Objective-C and C++ try and help programmers solve tricky problems using something called <b>“Object Oriented Programming” (OOP)</b>. That's where the “Objective” part in Objective-C comes from. OOP was really good at solving the kinds of problems we had back in the 1990's.<br />
<br />
OOP is so successful because it helps teams of programmers work together and co-ordinate. Any time you have a large group of programmers working together, especially on the very largest software projects, you'll find that they're using some version of OOP to help them all co-operate.<br />
<br />
<hr />
<br />
Because both C++ and Objective-C have a shared history in C, if you wanted, you could take a C program and pretend that's it's C++ or Objective-C and most of the time that might even work!<br />
<br />
What really happens though, is that because the languages are so different, it changes the way that programmers think about their problems. This means that C programs, C++ programs and Objective-C programs all end up looking quite different from each other, even when programmers are trying to solve the same problem. ( <a href="https://en.wikipedia.org/wiki/Linguistic_relativity">See also: Sapir–Whorf hypothesis</a>. )<br />
<br />
<hr />
<br />
Which brings us to <b>C#</b>. C# isn't really a C language at all. There's actually another programming language called <b>Java</b> that used to be really popular around the year 2000 because it helped with the OOP problem much better than anything else. A company called Microsoft wanted to make something that was kind of like Java, but kind of different too. So they created C# to work a lot like Java, but changed things up a little bit so that it looks kinda like C if you squint.<br />
<br />
<hr />
<br />
Well here we are in 2010's, and the kind of problems programmers are facing have changed again. It turns out that using OOP can sometimes combine with other problems to make them more complicated, graphics problems like “threading” and “latency” or the special problems that come up with Artificial Intelligence for example.<br />
<br />
While we have newer languages like “Cg”, “R” or “Python” that try and address some of these newer problems straight on, it turns out the simplicity of C allows individual programmers to focus more clearly on the problems that are important to them. That's why C is still popular today, even though it's the oldest of the 4.<br />
<br />
<hr />
<br />
<span style="font-size: large;"><b>TL;DR</b>: C is really simple. C++ and Objective-C are kind of similar because they're both C with extra stuff for “Object Oriented Programming” (OOP). C# is the oddball because it isn't really a C language at all, it's more like Microsoft's version of “Java”.</span><br />
<br />
<hr />
<br />
Source: Am programmer.missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com1tag:blogger.com,1999:blog-6140632138569689510.post-87941866278732289482015-11-26T22:32:00.000-08:002015-11-27T02:11:16.570-08:00The Cap Theorem and Quantum Gravity<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="line-height: 100%;">Apologies in advance, this post is both extremely technical in multiple fields, and woefully incomplete, and not nearly as humorous as it ought to be. Dragons be here. I'm incredibly sorry.</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<h3 style="line-height: 100%; margin-bottom: 0cm;">
CAP Theorem for distributed systems</h3>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<a href="https://en.wikipedia.org/wiki/CAP_theorem" target="_blank">Brewer's CAP Theorem</a> tells us that every distributed computer system must sacrifice at least one of these properties:</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
</div>
<ul>
<li><span style="line-height: 100%;">C: Consistency</span></li>
<li><span style="line-height: 100%;">A: Availability</span></li>
<li><span style="line-height: 100%;">P: Partition Tolerance.</span></li>
</ul>
<div style="line-height: 100%; margin-bottom: 0cm;">
Astonishingly, if we view the universe as a distributed system, then <a href="https://en.wikipedia.org/wiki/Quantum_field_theory" target="_blank">Quantum Field Theory</a> appears to have (analogues of) each of the three properties from the CAP theorem. But at what cost? Paradoxes. So many paradoxes. The <a href="https://en.wikipedia.org/wiki/Double-slit_experiment" target="_blank">double slit experiment</a>, the <a href="https://en.wikipedia.org/wiki/Twin_paradox" target="_blank">twin paradox</a>, the <a href="https://en.wikipedia.org/wiki/EPR_paradox" target="_blank">EPR</a> “spooky action at a distance” paradox. Many many more. What if QFT adds to the CAP theorem a fourth property we could sacrifice:</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
</div>
<ul>
<li><span style="line-height: 100%;">C: Consistency</span></li>
<li><span style="line-height: 100%;">A: Availability</span></li>
<li><span style="line-height: 100%;">P: Partition Tolerance</span></li>
<li><span style="line-height: 100%;">T: Time Never Flows Backwards (!!!)</span></li>
</ul>
<h3 style="line-height: 100%; margin-bottom: 0cm;">
One Million Boulders</h3>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Lets look at that last one, Time Never Flows Backwards. Suppose, inside a computer, we're trying to simulate one million boulders rolling down a mountain side. At every time step, we need to generate all the potential collisions between those million boulders, and then process them in the order in which the collision occurs. You're familiar with <a href="https://en.wikipedia.org/wiki/Newton%27s_cradle" target="_blank">Newton's cradle</a>? Every one of those collisions can change the magnitude, and order, of any subsequent collision. And worse, round-off error when <a href="https://en.wikipedia.org/wiki/Dicing" target="_blank">dicing</a> the time steps means that a collision over *here* can affect a collision over *there*.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br />
<div style="text-align: right;">
(All the gory details can be found <a href="http://www.merl.com/publications/docs/TR2000-17.pdf" target="_blank">here</a>.)</div>
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Starting to sound a little bit like quantum dynamics right?</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
So how do we solve it efficiently? By briefly reversing the arrow of time. We find all the collisions between those boulders in a given timestep, then, optimistically, we solve each boulder independently (“in parallel”) based on it's known potential collisions, as if the order of collisions didn't matter. Then we do a “Fix-Up” phase where we wind the time step backwards and correct any of the boulders where (A) the collision order was incorrect, and (B) the energy of the correction is above a certain tolerance. (In practice the tolerance is very small, this tolerance only serves to prevent certain pathological worst-cases)</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Starting to sound a *lot* like quantum dynamics...</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<h3 style="line-height: 100%; margin-bottom: 0cm;">
Spinfoam</h3>
<div style="line-height: 100%; margin-bottom: 0cm;">
So imagine the <a href="https://en.wikipedia.org/wiki/Spin_foam" target="_blank">spinfoam</a>. In my mind, I visualize it something like this:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjZwfciLjvxNw5GEUsJIAjyPIBLFjpMM41Ffz6ginA56zWaGOdf4RxE1WMFyxYoICtX8Dpp-VGZivB9_yN5c6GGreOdxL06ehtczzeReqxG5txpedUIUn0THaTeNwUSL0eQFwDvqAIQ70/s1600/SpinFoam.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjZwfciLjvxNw5GEUsJIAjyPIBLFjpMM41Ffz6ginA56zWaGOdf4RxE1WMFyxYoICtX8Dpp-VGZivB9_yN5c6GGreOdxL06ehtczzeReqxG5txpedUIUn0THaTeNwUSL0eQFwDvqAIQ70/s640/SpinFoam.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Spinfoam sketch, incomplete</td></tr>
</tbody></table>
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
In <a href="https://en.wikipedia.org/wiki/Quantum_chromodynamics" target="_blank">Quantum Chromo Dynamics</a> terms, every face you can see is “Colourless” = (Red + Green + Blue == Red + Red + AntiRed + Green + Blue). In this diagram, the past is down. It's the rigid fixed lattice and appears unchangable. The future is a soup of these faces to the top of the diagram, and the “present” is the coalescing region where the mobile soup phase-transitions into a fixed lattice. Naturally, each edge is the <a href="https://en.wikipedia.org/wiki/Planck_length" target="_blank">Planck length</a>, equivalently <a href="https://en.wikipedia.org/wiki/Planck_time" target="_blank">Plank time</a>.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
You can even see what we'd call a 'particle', maybe an electron or a neutrino, zipping along at close to the speed of light. In the spinfoam, it appears as a disturbance in the otherwise orderly lattice.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br />
<ul>
<li><span style="line-height: 100%;"><technical><span style="font-size: xx-small;"> In this diagram, the colours satisfy the </span></span><a href="https://en.wikipedia.org/wiki/Pauli_exclusion_principle" style="font-size: x-small; line-height: 100%;" target="_blank">Pauli exclusion principle</a><span style="font-size: xx-small; line-height: 100%;">. To represent </span><a href="https://en.wikipedia.org/wiki/Boson" style="font-size: x-small; line-height: 100%;" target="_blank">bosons</a><span style="font-size: xx-small; line-height: 100%;">, simply write integer values at every vertex, and require every cycle-over-edges to sum to zero.</span></li>
<li><span style="font-size: xx-small; line-height: 100%;">This 2D diagram with vertices, edges and faces represents {1xspace+1xtime} dimensions. If we axiomatically accept the </span><a href="https://en.wikipedia.org/wiki/Holographic_principle" style="font-size: x-small; line-height: 100%;" target="_blank">Holographic Principle</a><span style="line-height: 100%;"><span style="font-size: xx-small;">, then it might be possible to represent {3xspace+1xtime} dimensions using only vertices, edges, faces and solids.</span></technical></span></li>
</ul>
</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Notice too that, at least in the bottom of the diagram (“past”), the laws of physics are <a href="https://en.wikipedia.org/wiki/CPT_symmetry" target="_blank">symmetric</a>, and <a href="https://en.wikipedia.org/wiki/Rotational_invariance" target="_blank">invariant</a> under rotations through both time and space. Despite this local invariance, the time dimension can still be identified by it's global properties. The <a href="https://en.wikipedia.org/wiki/Arrow_of_time" target="_blank">arrow of time</a>, <a href="https://en.wikipedia.org/wiki/Entropy" target="_blank">entropy</a> etc, really does exist and has physical meaning.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<h3 style="line-height: 100%; margin-bottom: 0cm;">
Mass</h3>
<div style="line-height: 100%; margin-bottom: 0cm;">
What would happen if we tried to simulate this spinfoam in a computer? Well, most obvious to me, is that 'time' in the simulation does not correlate with the amount of computation required to run the simulation. Indeed, the computation required to run the simulation depends primarily on the search activity to coalesce the soup, and it should be easy to find a computation model where that search activity has a cost that matches <a href="https://en.wikipedia.org/wiki/General_relativity" target="_blank">Einstein's General Theory of Relativity</a>. i.e. the curvature of a region of space is related to the amount of mass in that region, <b>G = m . r<sup>-2</sup></b></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<h3 style="line-height: 100%; margin-bottom: 0cm;">
Speed</h3>
<div style="line-height: 100%; margin-bottom: 0cm;">
Now lets take that simulation, and instead of running it on one single computer, we instead run it on a <i>distributed</i> computer system. Suddenly, the <a href="https://en.wikipedia.org/wiki/CAP_theorem" target="_blank">CAP theorem</a> applies, and our simulation must sacrifice <b>C</b>, or <b>A</b>, or <b>P</b>.... or.... or..... or... <b>T</b>? What if we could sometimes run our simulation backwards just for a moment, the same as we did when "Fixing up" the simulate of those million boulders. When something doesn't fit, just for a little bit, we'd dissolve that fixed lattice of the past and turn it back into the mobile soup of the future, then reform the lattice into a consistent whole. <br />
<span style="line-height: 100%;">From inside the simulation, we'd never be able to send information back into the past (That would be a </span><b style="line-height: 100%;">C </b><span style="line-height: 100%;">violation!), and yet we'd still get “spooky action at a distance” and all those other paradoxes.</span><br />
<span style="line-height: 100%;">But at what cost? Well, surprisingly, only a performance hit. Again, it should be easy to find a model of distributed computation overhead where this performance hit is in exact agreement with </span><a href="https://en.wikipedia.org/wiki/Special_relativity" style="line-height: 100%;" target="_blank">Einstein's *Special* Theory of Relativity</a><span style="line-height: 100%;">. Specifically, it's the </span><a href="https://en.wikipedia.org/wiki/Lorentz_transformation" style="line-height: 100%;" target="_blank">Lorentz Transform</a><span style="line-height: 100%;">, </span><b>γ = 1 </b><b style="line-height: 100%;">/ sqrt(1-v<sup>2</sup>.c<sup>-2</sup>)</b></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<h3 style="line-height: 100%; margin-bottom: 0cm;">
Intermission</h3>
<div style="line-height: 100%; margin-bottom: 0cm;">
Okay, big deep breath. The plot-twist is coming up soon. Brace yourself.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<h3 style="line-height: 100%; margin-bottom: 0cm;">
String Theory (Science Fiction)</h3>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Almost everything I've written above isn't new or novel. It's just a rehash of various discarded <a href="https://en.wikipedia.org/wiki/String_theory" target="_blank">String-Theory</a> ideas from the 90s, but with different names and labels. From an experimentalist physicists point of view, String Theory is just not that interesting. In terms of knowing more about the universe we live in, String Theory is pretty much at a dead end. Why? Because it's not <a href="https://en.wikipedia.org/wiki/Falsifiability" target="_blank">*testable*</a>. We can't devise an experiment in the lab to determine if any one of the thousands of competing String Theories makes predictions which match our unique reality. If your theory isn't testable, if there's no way to determine if you theory approximates our universe better than the alternatives, then that's not "Science" with a capital 'S', it's more like Science Fiction with a whole lot more math.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<h3 style="line-height: 100%; margin-bottom: 0cm;">
Plot Twist</h3>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
So here's the plot-twist: <b>CAP Theorem + QFT is testable</b>.<br />
Here's how: Take that exact same familiar double slit experiment we all faithfully reproduced when we first found out about Quantum Mechanics.<br />
<br />
<br />
<ul>
<li><span style="line-height: 100%;">Setup-1: Use one slit, fire the wave/particle, measure the diffraction. (Gaussian)</span></li>
<li><span style="line-height: 100%;">Setup-2: Use two slits, fire the wave/particle, measure the diffraction. (Interference pattern)</span></li>
</ul>
</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Now, if we compare Setup-1 with Setup-2, if CAP + QFT is true, then Setup-2 will suffer a tiny time-dilation associated with resolving the CAP constraints. If CAP+QFT is true, we could toggle between Setup-1 and Setup-2 and measure the tiny difference in time dilation.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
How tiny? So tiny no-one has ever noticed it before.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
...so tiny, it would be much much smaller than the time-dilation associated with the mass of the photon itself.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
......<span style="font-size: x-small;">so <i>tiny</i></span>, but, at least in theory, <span style="font-size: large;">so <i>measurable</i></span>.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
What happens if we go into the lab and measure the time dilation difference between Setup-1 and Setup-2, and that difference turns out to be non-zero?</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<h3 style="line-height: 100%; margin-bottom: 0cm;">
Quantum Gravity and Friends.</h3>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
So yeah, that's a testable theory of quantum gravity. It neatly explains why gravity is so weak compared with the other forces (aka <a href="https://en.wikipedia.org/wiki/Hierarchy_problem" target="_blank">the Hierarchy problem</a>), and dramatically simplifies the particle zoo.<br />
<br />
Furthermore, this theorem is fully consistent with the <a href="https://en.wikipedia.org/wiki/Copenhagen_interpretation" target="_blank">Copenhagen Interpretation</a>, and even builds on it! By contrast, In this formulation, the <a href="https://en.wikipedia.org/wiki/Copenhagen_interpretation" target="_blank">many-worlds alternative</a>, however appears to have a vanishingly strict interpretation.<br />
<br />
Black holes? Yip.. (I'll let you puzzle that one through, it's actually quite cute :) <a href="https://en.wikipedia.org/wiki/Naked_singularity" target="_blank">Naked singularities</a>? Nope.<br />
<br />
It neatly explains the uncertainty principle. It's truly a quantum theory from the get-go. The randomness is real ("<a href="https://en.wikipedia.org/wiki/Hidden_variable_theory" target="_blank">no hidden variables</a>"), it's even required, but it's certainly not arbitrary or capricious.<br />
<br />
All those crazy dimensions from String Theory? Oh yeah, the dimensionality is there, but they're no longer spatial in nature, they're more like properties stacked on the spinfoam.<br />
<br />
There's even some tantalising hints on the nature of dark matter and dark energy and inflation in the early universe..<br />
<br />
Anyways, I've probably said way too much, a<span style="line-height: 100%;">s always, if you have any questions, queries or opinions, please let me know in the comments section below!</span><br />
<span style="line-height: 100%;"><br /></span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com2tag:blogger.com,1999:blog-6140632138569689510.post-86752078414206098232015-09-12T18:16:00.000-07:002015-09-13T04:39:45.450-07:00Keeping our kids safe, with better level design and video games.<div style="line-height: 100%; margin-bottom: 0cm;">
Our local bus stop used to have a safety problem. All the school kids would line up, frantic to
be first on the bus.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
The front kid would
stand with their toes hanging over the curb. The next one behind
them, peering over their shoulder, and so on and so forth... They
would stand that way in pseudo-formation, for agonizing minutes at a time,
as the cars zipped past on the morning commute. Finally the enormous
school bus would swing in and stop mere centimeters away from the
nose of the kid in front.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Just one tiny
fumble, or even just one loud boisterous dog, could have spelled tragedy.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
I spoke about it
with the other Mums and Dads. I know from designing levels in
video games that there's an easy fix we use for these kind of problems. I told them someone could simply paint a yellow “Do Not Cross” line on the ground, and the
kids would naturally do the rest, even when the parents weren't around.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
For the record, I've
never defaced public property, nor would I encourage anyone else to
do the same.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Yet some anonymous
do-gooder has gone and done just that:</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8I0zGdyDlzF54u77gr1KmlQ8K2hcKRiIdy8oThprRlj_vLuMwyGbVvya_KQ81yT55Q0pKSW_up9Sg-uaDuQJ9MX_R4GUDk5R-Ig7vdVULhZHIULC7zpvsgVbcMagOaU5IB50NA3gS6D4/s1600/YellowLine.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8I0zGdyDlzF54u77gr1KmlQ8K2hcKRiIdy8oThprRlj_vLuMwyGbVvya_KQ81yT55Q0pKSW_up9Sg-uaDuQJ9MX_R4GUDk5R-Ig7vdVULhZHIULC7zpvsgVbcMagOaU5IB50NA3gS6D4/s640/YellowLine.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Vigilante safety engineering - a yellow "Do Not Cross" line has been painted at this local school bus stop by an anonymous parent, obviously over the concerns about child safety.</td></tr>
</tbody></table>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
All the kids now line up
a safe distance from the road, and the possibility of tragedy at our local bus stop has been dramatically reduced.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Well sure, this act of civil disobedience might
not be able to protect the neighbourhood kids from the harmful rays
of the sun, mindless advertising, unvaccinated kids or bad
language... but at least now the kids at my local bus stop line up
further away from the traffic.</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<br />
<div style="line-height: 100%; margin-bottom: 0cm;">
If you have a
concerns about traffic safety at your bus stop, here's one small
thing that any anonymous do-gooder can do, that will actually make a
difference, all thanks to better level design and video games.</div>
missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com1tag:blogger.com,1999:blog-6140632138569689510.post-21995835961412764672015-03-28T01:04:00.001-07:002015-03-28T01:06:18.863-07:00Pixel ScalingI'm converting the maps from the amiga version of Super Skidmarks to work on mobile devices for Skidmarks 2015.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqcFtxgA-YCWXLqg-aO_2fewGyQHT8Bn2SU8za63Yfii1R0rClrUTesM5y44_cRbX0v9wsybj95gzS-CGi4bKTJOwbUaiqzV2ZqxSALxEetLV0DNurBFWL3NzjG59cR86j5T4Zjgd4kTA/s1600/DecoderTest.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqcFtxgA-YCWXLqg-aO_2fewGyQHT8Bn2SU8za63Yfii1R0rClrUTesM5y44_cRbX0v9wsybj95gzS-CGi4bKTJOwbUaiqzV2ZqxSALxEetLV0DNurBFWL3NzjG59cR86j5T4Zjgd4kTA/s1600/DecoderTest.jpg" height="322" width="640" /></a></div>
<br />
<br />
Normally when we scale an image, we treat it as a continuous tone image, like a photograph:<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKqNAtsLfRnYLKLWrww6kKG0X8HIg12KA8mmGFc2Q0cn_Y7-zhvS8V-vspERcl7Qr3b7_QzBWty4LXG2M6zuRXjIexk98MO3qWKucDar96llodENmyUP73yS77LAn29jqLP5sEsUzLW4I/s1600/DecoderTest2.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKqNAtsLfRnYLKLWrww6kKG0X8HIg12KA8mmGFc2Q0cn_Y7-zhvS8V-vspERcl7Qr3b7_QzBWty4LXG2M6zuRXjIexk98MO3qWKucDar96llodENmyUP73yS77LAn29jqLP5sEsUzLW4I/s1600/DecoderTest2.jpg" height="580" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Cubic</td></tr>
</tbody></table>
One option is to just leave the pixels as is. It gives it a retro feel, but doesn't really capture what computer monitors in the 90s used to look like. We used to call this mode "fatbits":<br />
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3utqWot_dhq__Qzkvt2PQ2RdyzyXcY0k696a4mtUfHq5T_YToK_KOiHGftajy1V6Y65EiYXAZrCFd53PVpOh-CitLr-FjlFEgz8H4EBiJHMT4s0SmUwuPzmaIPXXLH1hDI5Ir-156MjY/s1600/DecoderTest3.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3utqWot_dhq__Qzkvt2PQ2RdyzyXcY0k696a4mtUfHq5T_YToK_KOiHGftajy1V6Y65EiYXAZrCFd53PVpOh-CitLr-FjlFEgz8H4EBiJHMT4s0SmUwuPzmaIPXXLH1hDI5Ir-156MjY/s1600/DecoderTest3.jpg" height="580" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Fatbits</td></tr>
</tbody></table>
<br />
And yet a third way is to use a pixel-art rescaling algorithm, like <a href="http://sourceforge.net/projects/xbrz/" target="_blank">xBRZ</a>.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivp8k0Vsj-8bYVwhcmH-obp_ckYhf7DdMUUEB9HyduLg7vkjWSLcU1X_sHGWyPoksx_HbrJQawWz3c_Xv4Ioh-wdvreh5c7jtCau2ogsebv1OVHFrv8WuXcgCYRNJ7Fza9pIGRwXR1ZEw/s1600/Decoder2.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivp8k0Vsj-8bYVwhcmH-obp_ckYhf7DdMUUEB9HyduLg7vkjWSLcU1X_sHGWyPoksx_HbrJQawWz3c_Xv4Ioh-wdvreh5c7jtCau2ogsebv1OVHFrv8WuXcgCYRNJ7Fza9pIGRwXR1ZEw/s1600/Decoder2.jpg" height="598" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">xBRZ</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Click through on the images to see full res.<br />
<br />
Which do you think I should use? Any other techniques I should consider?missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com3tag:blogger.com,1999:blog-6140632138569689510.post-25261041112050243942015-03-21T14:24:00.002-07:002015-03-21T15:07:58.627-07:00Time PressureA buddy of mine was sharing some cool ideas for a new game when we got to talking about Time Pressure. "Blog post!” I thought!<br />
<br />
<h3>
Time Pressure in Games</h3>
<br />
If you think of classic games, like Chess, or Tennis, you'll find that most classic games have some sort of time pressure mechanic. A skilled player can apply this pressure to increase the number of “unforced errors” of their opponent.<br />
<br />
<img align="right" src="http://upload.wikimedia.org/wikipedia/commons/thumb/2/27/Halla_in_white_away_jersey_vs_Oji_Eagles.jpg/320px-Halla_in_white_away_jersey_vs_Oji_Eagles.jpg" /><br />
<br />
A great example of time pressure in Ice Hockey is the “Power Play”. When a player commits a penalty, they're sent to the penalty box, giving a 5-4 player advantage on the ice to the other team. As the penalty timer ticks down to zero, the attacking team is under increasing pressure to score a goal and take advantage of the situation.<br />
<br />
For a hockey fan, watching at home on TV, the “Power Play” also increases pressure. Either there will be a goal, or the attacking team will make a mistake and squander the opportunity. In either case, the pressure is on the spectator to keenly observe and interpret the action before the penalty clock runs down to zero.<br />
<br />
In the casual games, “Dumb Ways To Die” and “WarioWare”, the player must complete amusing tasks, but under tighter and tighter time constraints. At least in the early stages of play, the player actions would be easy to do, if not for the added pressure that comes from the timer.<br />
<br />
Curiously, in these types of games, as the player skill increases, the gameplay shifts and becomes more reaction and twitch based. When played at this level, the time pressure is almost completely removed. It's similar to the way the rich, multi layered time pressures in a game like Tennis are largely absent from Ping Pong, which is essentially the twitch-based version of the same game.<br />
<br />
<a href="http://scooterboygame.com/"> <img align="right" src="http://scooterboygame.com/image/IconSB1024.png" width="128" /> </a><br />
My mobile game, <a href="http://scooterboygame.com/" target="_blank">ScooterBoy</a>, is a mashup between two popular genres, the endless runner and slicing games. The twist is that when the player slices a spore to get points and combos, the same action also causes ScooterBoy to jump/duck/change lanes. In essence, you're playing two different games simultaneously. For skilled ScooterBoy players, the endless runner determines the length of time for each game, while it's your ability to make combos in the slicing game which most affect your score. In this way, in ScooterBoy, the endless runner acts to apply time pressure on the slicing game.<br />
<br />
<h3>
Time Pressure == A Complication</h3>
The common theme across all of these games is that time pressure adds a complication to an already fun activity.<br />
<br />
As a game designer, we can turn this observation inside out. If we know that adding time pressure is equivalent to adding a complication, then we are obliged to verify that our game design is still fun, even when the time pressure is removed.<br />
<br />
Indeed, if we're following the (so called) “<a href="http://www.gamasutra.com/view/feature/167214/rational_design_the_core_of_.php" target="_blank">Rational Game Design</a>” principles, we should be able to strip our game down to it's core, removing all the complications... Then we add the complications back in, one at a time and in combinations, in order to maximise player enjoyment.<br />
<br />
Under this framework, Time Pressure is just one of many different types of complications we could add, and this means (in general) we can assume <i>a priori</i>, that we could add and remove Time Pressure at any time to our game design, without affecting the strength of the design itself.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFaBcpKIHQ8vSOM_Gm3u0URNQ-s9aYElj5dasWVjFPpRKF-KIauvKkrMIx1-ZwFYcdQbSmRRn9LBFeg3fGf2nNfh2rumNkp33VLjwJOxqC8EjNRvMnTXtYK6Q6jK3CTQtaWnGrbomyynA/s1600/MoTimePressure.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFaBcpKIHQ8vSOM_Gm3u0URNQ-s9aYElj5dasWVjFPpRKF-KIauvKkrMIx1-ZwFYcdQbSmRRn9LBFeg3fGf2nNfh2rumNkp33VLjwJOxqC8EjNRvMnTXtYK6Q6jK3CTQtaWnGrbomyynA/s1600/MoTimePressure.png" height="198" width="320" /></a></div>
<br />
Phrased another way, <b>Time Pressure</b> acts as a <b>multiplier</b> to increases the <b>intensity</b> of your underlying experience.<br />
<br />
<h3>
Time Pressure and Difficulty</h3>
Lets drill down to the first few moments of your game. First impressions. In free-to-play, these first few minutes of gameplay is where you make or lose your players.<br />
<br />
For players familiar with your genre, the time pressure does nothing. They zip through the first few levels with perfect scores, and your effort implementing and balancing the time pressure mechanic has contributed nothing.<br />
<br />
For less skilled players, those unfamiliar with your genre, the time pressure adds confusion and failure, additional UI, and worst of all, the pressure increases unforced errors and perceived difficulty. All your hard work to implement time pressure serves to drive off more casual players.<br />
<br />
A time-pressure mechanic (generally) makes things *harder* for weaker players, and leaves stronger players unchanged.<br />
<br />
This is the exact opposite of how difficulty scaling is supposed to work.<br />
<br />
You can compound this disaster by awarding the player a power-up for completing a level in a short amount of time. Here you are explicitly making the game easier for your most skilled players.<br />
<br />
Sandbox games with broad market appeal, I'm thinking games like “Disney Infinity” and “Grand Theft Auto” here, commonly avoid these traps by making time pressure optional. There are timed challenges on the map which the player can initiate, but the player isn't required to complete them to advance the player's personal narrative.<br />
<br />
<h3>
Time Pressure as Exotic gameplay</h3>
So how do us Indies make time pressure fresh and original? We can take inspiration from some recent games which use the passage of time to completely subvert conventional notions of gameplay. <br />
<br />
<img align="right" src="http://braid-game.com/icon_images/killsign.png" /><br />
At first glance, “Braid” appears to be a platformer, but it's actually a puzzle game that explores all manner of time based mechanics.<br />
<br />
I won't spoil it for you, but “Five Nights At Freddies” has some amazing time-pressure mechanics where the player has extremely minimal interaction with the game.<br />
<br />
I'm sure there's lots more examples you can share with us in the comments below.<br />
<br />
<b>Time Pressure, it's been done! Time to do something different.</b>missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-52299400216012940832015-01-29T12:17:00.003-08:002015-01-29T12:17:58.264-08:00C++ ScreencastTrying something different, reformatting a binary search in C++<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/HyvyT4AS1H8" width="560"></iframe>missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-66096926305225982612015-01-17T16:14:00.002-08:002015-11-25T23:13:11.490-08:00Whitespace, you're doing it wrong.What if there was a scientific, objective way to format the whitespace in your current programming language?<br />
<div>
<div>
<br /></div>
<div>
Received wisdom tells us that choice of formatting styles is a purely subjective choice. The same as choosing a coffee blend, or finding the best way to paint your <a href="http://bikeshed.com/">bikeshed</a>.</div>
<div>
<br /></div>
<div>
What if they lied?</div>
<div>
<br /></div>
<div>
What if it was indeed possible to develop a framework to measure, compare and contrast formatting styles in a rational, objective way by applying the Scientific Method<sup>tm</sup>?</div>
<div>
<br /></div>
<div>
As a community, we could then migrate towards a formatting style based on a series of measurable scientific tests, such that every competent programmer would agree on the outcome, even when that outcome differed from their own personal preference.</div>
<div>
<br /></div>
<div>
We might even then invoke <a href="http://en.wikipedia.org/wiki/Stigler%27s_law_of_eponymy">Stigler's law</a> and name such a formatting style “<b>The Kolmogorov Style</b>” for formatting programming languages.</div>
<div>
<br /></div>
<div>
What would you do if your favourite subjective choice turned out to be different from the Kolmogorov Style? What would you be forced to do, if I could scientifically prove that your whitespace choices, what you thought was your subjective preference, was objectively wrong?</div>
<div>
<br /></div>
<div>
Read on if you're genuinely brave enough to challenge your preconceptions...</div>
<div>
<br /></div>
<div>
<span style="font-size: large;"><b>TRIGGER WARNINGS : Unicode, indentation, tabs, newlines, braces, Kolmogorov complexity</b></span></div>
<div>
<br /></div>
<div>
<i><span style="color: red;">Warning : This post requires unicode to read correctly. If your browser does not support unicode, please stop reading now.</span></i></div>
<div>
<br /></div>
<div>
<br />
<ul>
<li>Note 1 : This blogpost will be continuously updated in response to reader feedback. Because Peer Review.</li>
<li>Note 2 : Formatting conventions and other terminology follow <a href="http://en.wikipedia.org/wiki/Indent_style">wikipedia</a>.</li>
<li>Note 3 : I'm using C/C++ merely for convenience here. Obviously this extends to other (programming) languages in a natural way.</li>
<li>Note 4 : It seems some brave souls are actually attempting research of this sort : <a href="http://ppig.org/sites/default/files/2015-PPIG-26th-Sarkar.pdf">http://ppig.org/sites/default/files/2015-PPIG-26th-Sarkar.pdf</a> Way to go guys!</li>
</ul>
</div>
<div>
<br /></div>
<div>
<h3>
Existence proof</h3>
</div>
<div>
This is going to take a little bit of work, so I'm going to proceed in stages.</div>
<div>
<br /></div>
<div>
First up, I'm going to construct what theoretical mathematicians call an '<b>existence proof</b>'. That's a standalone proof where I show it is possible to find an objective test of a formatting style, such that 100% of programmers will reach the same conclusion. The objective test won't be convincing! It's not intended to be convincing. The point of this section merely illustrates that it is <b>possible</b> to construct at least one objective test to make a decision between alternative formatting options. Only once we have our existence proof, will we be able start our search for the best objective tests to use.</div>
<div>
<br /></div>
<div>
As a pure hypothetical for this section, suppose we're starting a completely new project, purely for our own personal enjoyment, and we're trying to decide if we should indent using the TAB character, or indent using 4xSPACE.<br />
<br />
For our objective metric, we will measure the disk space required to store the code, with smaller being better.</div>
<div>
<br /></div>
<div>
We know that the TAB character ('\t') is 1 byte, and 4xSPACE, (' ') takes up 4 bytes.</div>
<div>
<br /></div>
<div>
Now, here's the part where I apply the scientific method! I select a representative source file from my hard drive, and prepare two versions, one with TAB indentation, and one with 4xSPACE indentation.</div>
<div>
<br /></div>
<div>
This particular file happened to have 2654 tabs, so we can cross-check :</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>RandomCPPFileTAB.cpp : 30,430 bytes</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>RandomCPPFile4xSPACE.cpp : 38,392 bytes</span></div>
<div>
<br /></div>
<div>
The results of my experiment showed the 4xSPACE version of this file is 26% larger than the TAB version.</div>
<div>
<br /></div>
<div>
I urge you to apply the scientific method and actually perform this experiment to determine if it is repeatable!</div>
<div>
<br /></div>
<div>
Extrapolating from this single data point(!), we expect that source files which use 4xSPACE would, on average, take up a larger amount of disk space, somewhere in the ballpark of 20% - 30% more.</div>
<div>
<br /></div>
<div>
Any competent C++ programmer can follow this chain of reasoning and agree that C++ files which use 4xSPACE are never smaller than the equivalent TAB version.</div>
<div>
<br /></div>
<div>
Crucially, my claim is that everybody who competently performs this particular objective test will obtain this same result (TAB beats 4xSPACE), even if they personally prefer 4xSPACE over TAB.</div>
<div>
<br /></div>
<div>
Now, before y'all start complaining that I chose an unfair metric, let me just repeat : <b>This is an existence proof</b>.</div>
<div>
<br /></div>
<div>
The entire point of this section is to establish the following hypothesis : “There exists at least one <b>objective test</b> which can be used to make a decision between alternative formatting options.”</div>
<div>
<br /></div>
<div>
Just to be 100% crystal clear, I'm not claiming this isolated test is sufficient for anyone to change spaces to tabs or vice versa! </div>
<div>
<br /></div>
<div>
The only point that I've proved is that it is possible for at least one objective test for whitespace stylistic concerns to actually exist, and therefore, by extension, it is <i>meaningful</i> to look for more.</div>
<div>
<br /></div>
<div>
(However, I feel obliged to point out that Kolmogorov Style does indeed use tabs instead of spaces for the C++ language. I certainly haven't proved it... But I think I can illustrate the fact by issuing the following challenge: If there exists even one objective scientific test against (i.e. 100% of competent C++ programmers would complete the test and choose 4xSPACE over TAB) then please post such a test in the comments below. I'll be sure to update this post if an objective scientific test does exist.)</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3>
Another example, Find in Files, :lgrep, Find in Workspace, M-x rgrep </h3>
</div>
<div>
Here's another motivating example, again purely for illustrative purposes. It's not intended to be convincing, the goal is simply to illustrate that it is <i>possible</i> to construct objective tests where 100% of competent programmers will reach the same conclusion about a formatting style, even if their personal preference is different.</div>
<div>
<br /></div>
<div>
Again, pure hypothetical, entirely new project, we're trying to decide between two ways to format a C++ class declarations:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Allman</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">:</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">public Style</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">{</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>//...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">};</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br />
</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Stroustrup : public Style {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>//...</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">};</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Every programming environment provides some facility for matching lines within a codebase, so our objective test will be : Which formatting style gives us more information about the class hierarchy, as a result of performing 'grep class *.h'. (i.e. Look in all files which have a .h suffix, and print out any line which contain the string 'class')</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Here's what the output might looks with the Allman style:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Adams</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Jackson</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Garbo</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Greta</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Douglas</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Michael1</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Michael2</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Jackie</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Kennedy</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Sam</span></div>
<div>
<br /></div>
<div>
And the same code, formatted with Stroustrup style:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Adams {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Jackson {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Garbo {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Greta : private Garbo {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Douglas {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Michael1 : public Douglas {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Michael2 : private Jackson {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Jackie : public Kennedy, private Onassis {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Kennedy {</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">class Sam : public Adams {</span></div>
<div>
<br /></div>
<div>
On this particular objective test, I claim that every competent C++ programmer will agree that the Stroustrup style gives more information, even if they personally prefer to use the Allman style.</div>
<div>
<br /></div>
<div>
Once again, if you're at all interested in the scientific method and have access to a C++ codebase, please do a 'find-in-files' or similar. Are you satisfied with the results? Would you have more or less information if your codebase was Allman/Stroustrup style? Please post your results below, especially if they are different!!<br />
<br />
<br />
<br />
<br />
<br /></div>
<hr />
<br />
<div>
<br /></div>
<div>
We're starting to get closer. We now have two examples of objective tests, and maybe we can even start to see a trend (remove redundant encodings).</div>
<div>
<br /></div>
<div>
We're also beginning to suspect there's probably many families of objective tests, and almost all of them are contradictory.</div>
<div>
<br /></div>
<div>
Take the famous <a href="http://bikeshed.com/" target="_blank">painting the bikeshed</a> problem, how many coats of paint should we use?</div>
<div>
<br />
<ul>
<li>Clearly 2 coats are objectively <b>better</b> than 1, because <b>durability</b>!</li>
<li>Clearly 2 coats are objectively <b>worse</b> than 1, because <b>cost</b>!</li>
</ul>
</div>
<div>
<br /></div>
<div>
Suddenly our objective tests are starting to look awfully subjective - given a universe of objective tests, how do we choose which are the best objective tests to apply?</div>
<div>
<br /></div>
<div>
To answer that, I'm going to need to introduce “Coding Atoms”.</div>
<div>
<br /></div>
<div>
<h3>
Introducing Coding Atoms</h3>
</div>
<div>
<div style="text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">Atom – indivisible</span></div>
</div>
<div>
<div style="text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">The smallest, indivisible constituent part or unit of something.</span></div>
</div>
<div>
<div style="text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">from Ancient Greek ἄτομος (átomos, “indivisible”)</span></div>
</div>
<div>
<div style="text-align: center;">
<br /></div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Allow me to introduce a simple C++ coding atom:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int</span></div>
<div>
<br /></div>
<div>
Just like in physics, we can look inside that 'atom', and see that it has 3 component parts, 'i', 'n', and 't'.</div>
<div>
<br /></div>
<div>
Let's look at the 6 possible permutations of those three parts, and verify that only one of them is valid C++:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>itn </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>nit </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>nti </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>tin</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>tni</span></div>
<div>
<br /></div>
<div>
Here's another way of probing our atom, we'll insert a pair of brackets and confirm that only when the “i”, “n” and “t” are adjacent do we have valid C++.</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>()int</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>(i)nt </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>(in)t</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>(int)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>i()nt</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>i(n)t</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>i(nt)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>in()t</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>in(t)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int()</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
The component parts of “int” are fused together in a special kind of way, we can't tear them apart, or insert things, or rearrange them and still have a meaningful C++ program.</div>
<div>
<br /></div>
<div>
That's what I'm talking about, when I use the term “coding atom”.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3>
Coding Atoms : Variable Declarations</h3>
</div>
<div>
Allow me to present another atom, a variable declaration using the <a href="http://c2.com/cgi/wiki?ResourceAcquisitionIsInitialization">Resource Acquisition Is Initialization (RAII)</a> principle:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int adams = 42;</span></div>
<div>
<br /></div>
<div>
Or if we substitute {■ : adams, □ : 42}, we can rewrite our atom like this :</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ■ = □;</span></div>
<div>
<br /></div>
<div>
Let's try permuting:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ■ = □;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>int ◻ = ■;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>■ = int ◻;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>; ■ int = ◻</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>■ int; = ◻</span></div>
<div>
<br /></div>
<div>
And inserting brackets:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ■ = (□);</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>(int ■) = ◻;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>(int ■) = ◻;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>int (■ = ◻);</span></div>
<div>
<br /></div>
<div>
In the same way that 'int' is a coding atom, this declaration is 'fused' together. We can't insert or rearrange into it and still have a meaningful C++ program.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Look what happens when we break RAII and split our atom across two lines:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ■;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>■ = □;</span></div>
<div>
<br /></div>
<div>
And permute:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>■ = □;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>int ■;</span></div>
<div>
<br /></div>
<div>
Or insert a pair of braces:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>{</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>int ■;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>■ = □;</span></div>
<div>
<br /></div>
<div>
Compiler errors for everyone!</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
OK, lets try two atoms, this time with comments</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ▲ = △; // triangle</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ■ = □; // square</span></div>
<div>
<br /></div>
<div>
Permuting and everything is awesome:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ■ = □; // square</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ▲ = △; // triangle</span></div>
<div>
<br /></div>
<div>
Rock on! Now braces! All good!</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ▲ = △; // triangle</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>{</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ■ = □; // square</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></div>
<div>
<br /></div>
<div>
But what if we split the atoms and try to write our comments like this.. maybe that's okay? :</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>// triangle</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ▲ = △;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>// square</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ■ = □;</span></div>
<div>
<br /></div>
<div>
Permuting, perhaps as a result of sorting the lines alphabetically :</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>// triangle</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>// square</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ■ = □;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ▲ = △;</span></div>
<div>
<br /></div>
<div>
Whoa, what just happened?!?! Did you just feel the cabin pressure drop? We've produced valid C++ code that compiles just fine, passes all our unit tests, and runs correctly … but our comments are disconnected from their roots and have become actively harmful to our understanding of the code.</div>
<div>
<br /></div>
<div>
These are some of the longest lived families of software defects – the ones where the executable isn't affected and our automatic tools don't notify us when a new problem has been created. This only happened because we allowed a newline to be <b>inside</b> our coding atom.</div>
<div>
<br /></div>
<div>
I know what you're thinking.. “Such a silly mistake would never make it into shipping code”. Well, anecdotally, in the short time since preparing this blogpost as a draft and actually posting it, I've located and repaired defects of exactly this type (on a live production codebase) on at least 4 occasions.</div>
<div>
<br /></div>
<div>
The take home for this section is : At least on this somewhat contrived example (the “reducing defects as a result of random line permutations of variable declarations” test), every single programmer, regardless of their own personal variable declaration preference, who competently performs this experiment, will agree that the best way to declare a variable is with everything on the same line. i.e.:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>int ▲ = △; // triangle</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3>
Coding Atoms : Mandatory Braces</h3>
</div>
<div>
<br /></div>
<div>
You're not going to like this one. Not one bit.</div>
<div>
<br /></div>
<div>
Here's the coding atom for an if statement.</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>if(●){</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>◎</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></div>
<div>
<br /></div>
<div>
What happens if we don't use braces at all?</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>if(●)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✗<span class="Apple-tab-span" style="white-space: pre;"> </span>◎</span></div>
<div>
<br /></div>
<div>
Disaster! Our ◎ atom has been torn apart! Observe:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">#define ◎ print(“Hello, World“); log(“Hello, Log”); </span></div>
<div>
<br /></div>
<div>
As a consequence of not using braces, we've opened ourselves to the possibility of splitting an atom and introducing bugs. I'll formalise this principle more fully in just a moment. But for right now, I'm just going to blurt out:</div>
<div>
<br /></div>
<div>
<i><span style="font-size: large;">For any given pair of C++ formatting styles which differ only in their usage of mandatory braces, the style using mandatory braces will be objectively better.</span></i></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
(Oh, you think I'm wrong on this one? First, go read <a href="http://avandeursen.com/2014/02/22/gotofail-security">about the gotofail bug</a> Once you think you've understood that, let me know why you think $X is more important that having your code run correctly.)</div>
<div>
<br /></div>
<div>
Anyway, lets press forward! There's an alternate way of formatting conditionals, where the opening brace occurs on a different line from the conditional. I'll come back to the problems with this example very shortly, but for now, I just want to identify the coding atom and move forward.</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>if(●)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>{</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>◎</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3>
Coding Atoms (part 3)</h3>
</div>
<div>
Here's a short list of some of the frequently encountered (C++) coding atoms:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>▵;//comment</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>int ▵=▵;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>if(▵){▵}</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>while(▵){▵}</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>for(▵;▵;▵){▵}</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>class ▵:public ▵{▵};</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><span class="Apple-tab-span" style="white-space: pre;"> </span>int ▵(▵,▵,▵,...)const;</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3>
Hypothesis Time</h3>
</div>
<div>
<br /></div>
<div>
So at this point, we hopefully have an intuitive feel for what a coding atom is (you can't split it up), and we have two examples of an objective test (100% of competent programmers reach the same conclusion, regardless of their personal preference) for formatting.</div>
<div>
<br /></div>
<div>
Allow my to present my central hypothesis:<br />
<br /></div>
<div>
<div style="text-align: center;">
<span style="font-size: large;">Central Hypothesis:</span></div>
</div>
<div>
<div style="text-align: center;">
<span style="font-size: large;">For any given pair of formatting styles,</span></div>
</div>
<div>
<div style="text-align: center;">
<span style="font-size: large;">which differ only on the relative placement between the conditional and opening brace, </span></div>
</div>
<div>
<div style="text-align: center;">
<span style="font-size: large;">the style where they are on the same line will be objectively better.</span></div>
</div>
<div>
<div style="text-align: center;">
<br /></div>
</div>
<div>
If we could prove this hypothesis, with just a little bit of imagination, we could use it to predict that the single-line family of styles (Stroustrup, BSD KNF, Lisp style, Ratliff, K&R, 1TBS) are objectively better than the multi-line variants (Kernel style, K&R style, Allman style, Whitesmiths, GNU style, Horstmann)<br />
<br />
<i>Edit: An earlier version of this blog used 'Theorem' instead of 'Hypothesis' in this section. My apologies for any confusion this may have caused.</i><br />
<i><br /></i>
I suspect an actual proof for this hypothesis would make use of the following two observations :<br />
<br /></div>
<div>
<h3>
Line-based world</h3>
</div>
<div>
<br /></div>
<div>
We live in a line-based ecosystem. Find-In-Files, line numbers, the #line directive. In unixland, we have grep, sort, uniq etc.</div>
<div>
<br /></div>
<div>
In this section I'm going to use 'git' as an example of a source code control system, but the same principle applies to perforce, mercurial, subversion, cvs etc ad infinitum</div>
<div>
<br /></div>
<div>
Here's an actual real world diff from my local repository :</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">diff --git a/Source/Base/Optimize.cpp b/Source/Base/Optimize.cpp</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">index d827540..7cd13b5 100644</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">--- a/Source/Base/Optimize.cpp</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">+++ b/Source/Base/Optimize.cpp</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">@@ -258,6 +258,8 @@ void SWOptimize::FindMinimumBFGS(){</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> }</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">-// swlog(SWRoleMin,"iter=%d\n",iter);</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">+ if(Verbosity>1){</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">+ swlog(SWRoleMin,"BFGS iter=%d\n",iter);</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">+ }</span></div>
<div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> CalcNumericJacobian(&jacobian);</span></div>
<div>
<br /></div>
<div>
There's nothing surprising about this, one line was deleted and 3 lines were added. That's how diffs work. There's nothing special about the choice of git here either.</div>
<div>
<br /></div>
<div>
Diffs are one thing. What happens when we merge?</div>
<div>
<br /></div>
<div>
Earlier, we looked at an objective test that took of the somewhat arbitrary form “reducing defects as a result of random line permutations”. Well it turns out, when we merge, that's exactly what is happening. We take two sets of line based changes (Adds and Removes) and we try to apply them both at the same time.</div>
<div>
<br /></div>
<div>
<h3>
A pecking order for Merge Problems.</h3>
</div>
<div>
<br /></div>
<div>
Suppose we're trying to merge two diffs. There's a number of outcomes that could happen, from best case to worst case, they are:</div>
<div>
<br /></div>
<div>
✔✔<span class="Apple-tab-span" style="white-space: pre;"> </span>Automatic merge succeeds, code compiles, all tests pass! everything works! Success!</div>
<div>
✗<span class="Apple-tab-span" style="white-space: pre;"> </span>Automatic merge fails, manual fix.</div>
<div>
✔✗<span class="Apple-tab-span" style="white-space: pre;"> </span>Automatic merge succeeds, code doesn't compile, manual fix.</div>
<div>
✔✗✗✗<span class="Apple-tab-span" style="white-space: pre;"> </span>Automatic merge succeeds, code compiles, some tests fail, lengthy manual fix.</div>
<div>
✔✔✗✗✗✗✗✗<span class="Apple-tab-span" style="white-space: pre;"> </span>Automatic merge succeeds, code compiles, all tests pass! dormant bug enters the system.</div>
<div>
<br /></div>
<div>
That last outcome is particularly insidious. Your tools told you everything was fine, but they secretly created a bug.</div>
<div>
Lets take a look at our '4-line if' statement, with the conditional and opening brace on separate lines:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>if(●)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>{</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>◎</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></div>
<div>
<br /></div>
<div>
You see where this is going right? That newline between the conditional and the opening brace? That's exactly the place where our merge tool will happily go ahead and insert new code.</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>if(●)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">!<span class="Apple-tab-span" style="white-space: pre;"> </span>▦</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>{</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">!<span class="Apple-tab-span" style="white-space: pre;"> </span>◎</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">✔<span class="Apple-tab-span" style="white-space: pre;"> </span>}</span></div>
<div>
<br /></div>
<div>
This is just horrible. The merge reported success and our code compiles just fine – yet the bug exists! We're down to our last lines of defence now such as unit tests and peer review. If they fail to detect the problem, then we're silently putting bugs into our codebase, purely as a consequence of our C++ formatting style.</div>
<div>
<br /></div>
<div>
How often does this happen? When I've been working in active codebases that use this style, I probably see this type of “successful” merge at least once or twice per week. It takes time to clean up, and with any change, there's always the chance of making mistakes and introducing more problems.</div>
<div>
<br /></div>
<div>
Let's put this in context. Suppose github or bitbucket randomly inserted bugs into your code, but didn't notify you. Or if your IDE would occasionally insert extra characters into the middle of your file, and save it, and not tell you about it. Even if it was just once or twice a year per user, wouldn't you try hard to find some way to fix it?</div>
<div>
<br /></div>
<div>
<h3>
Summary</h3>
</div>
<div>
Lets review:</div>
<div>
<br /></div>
<div>
<br />
<ul>
<li>I gave an existence proof, a simple objective test that every competent programmer can perform and get the same answer, even when it conflicts with their own personal opinion.</li>
</ul>
</div>
<div>
<br /></div>
<div>
<br />
<ul>
<li>I highlighted coding atoms, and demonstrated why we should try hard to stop them spanning multiple lines.</li>
</ul>
</div>
<div>
<br /></div>
<div>
So did I do it? Describe Kolmogorov Style, a profoundly new way of formatting programming languages, in a way that everyone can objectively agree on? Well of course not! Such a thing can't be done in just one tiny blogpost.</div>
<div>
<br /></div>
<div>
Instead, I managed to show that it is most likely <i>possible</i> to construct such a formatting style, and gave some hints in the direction I think that such a style might look like.<br />
<br /></div>
<div>
Keep in mind, even if such a style were to be fully enumerated and justified, there would still be many excellent reasons not to follow it. Maintaining consistency for one. Retraining for another. The existence of an objective standard does not require us to ignore subjective factors.</div>
<div>
<br /></div>
<div>
However, if this is you:</div>
<div>
<br />
<ul>
<li>Starting a new project.</li>
<li>Preparing your team's coding standard for the first time.</li>
<li>Developing the presentation layer of a text editor.</li>
<li>Creating the syntax for a new programming language. <i>(Especially this one!)</i></li>
</ul>
Then I <b>strongly</b> suggest you take the time to understand the principles embodied in this post :<br />
<br />
<ul>
<li>Reduce redundant encoding.</li>
<li>Don't split atoms across multiple lines.</li>
<li>Convert optional syntax to mandatory.</li>
</ul>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3>
Appendix A: Aesthetics? They matter right?</h3>
</div>
<div>
Absolutely! Whitespace is integral to the appearance of code when displayed on a computer monitor. It's fundamental to readability to have adequate white space around your code. I think it's a great thing to be able to isolate individual elements and examine them!</div>
<div>
<br /></div>
<div>
We need familiar whitespace because we're all pattern matching machines.</div>
<div>
<br /></div>
<div>
But the thing is, code doesn't live on computer monitors.</div>
<div>
<br /></div>
<div>
As I write this in 2015, the vast bulk of code lives in source code repositories. It's a collection of disembodied diffs and their associated merge histories.</div>
<div>
<br /></div>
<div>
We take a snapshot of that repository at an arbitrary moment in time and use that to construct a bytestream on our hard disk.</div>
<div>
<br /></div>
<div>
No one is asking you to interpret that raw bytestream directly. All of us use integrated programming environments, built on top of a graphical windowing system, which reformats that bytestream into an aesthetically pleasing onscreen presentation.</div>
<div>
<br /></div>
<div>
Take this bytestream : “””for(int i=0;i<10;i++){\n\tprintf("%d",i);\n}\n”””</div>
<div>
<br /></div>
<div>
Here's just a sampling of 3 different ways you might convert that byte stream into pixels:</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibJxgJCDMzMcUYsEjwNz2jsoU5R2mAnRk-1rGz5XfsxvkUAK2yDFfy9E3TwL03M8InQzZo8lqcvKrVhM-J0_B6RqqbBdL839mdLRPm_y1qi264p26D5DqjTmv2-dvH8ed2ZiwiWNTG7o8/s1600/LFHfJg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibJxgJCDMzMcUYsEjwNz2jsoU5R2mAnRk-1rGz5XfsxvkUAK2yDFfy9E3TwL03M8InQzZo8lqcvKrVhM-J0_B6RqqbBdL839mdLRPm_y1qi264p26D5DqjTmv2-dvH8ed2ZiwiWNTG7o8/s1600/LFHfJg.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfC9PTKigi87ambDchUTxXpIoY7Aquy0gTFHR5I1NpVRJOzJzF8RLWtaBCrD_7CUGd9GjVpjANACOp3v_Qd-68YTi3sgA67fFcJz8wjegOZp4qlosh0PVaHN0XobCLi4AkhlCbxcMfRfk/s1600/OcwHcx.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="82" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfC9PTKigi87ambDchUTxXpIoY7Aquy0gTFHR5I1NpVRJOzJzF8RLWtaBCrD_7CUGd9GjVpjANACOp3v_Qd-68YTi3sgA67fFcJz8wjegOZp4qlosh0PVaHN0XobCLi4AkhlCbxcMfRfk/s1600/OcwHcx.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzbAkIpnq98C5cUctDHkRew2DPDTW1svUOvnetI76BPrp2FgRpSv9JAI90tyI5ZrzoD3R1fAXDemQJ5f26ln8S5Q3hMkOk4x9Vv0fxSdPf-vQURm2N5BdIIRB3unVPn1US2oJ20UBwrb8/s1600/9DKWJB.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="113" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzbAkIpnq98C5cUctDHkRew2DPDTW1svUOvnetI76BPrp2FgRpSv9JAI90tyI5ZrzoD3R1fAXDemQJ5f26ln8S5Q3hMkOk4x9Vv0fxSdPf-vQURm2N5BdIIRB3unVPn1US2oJ20UBwrb8/s1600/9DKWJB.png" width="320" /></a></div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Look, I don't care if your IDE uses proportional fonts, or monospace fonts, or wingdings or braille. I don't care about your color scheme, your choice of syntax highlighting, your latest emacs macro, oh-my-zsh github, which scrolling plugins you've got installed, or which keys on your DVORAK keyboard binds to autocomplete. #YOLO.</div>
<div>
<br /></div>
<div>
But here's the rub. All of those choices are local to your machine. None of your local choices can leak on to our team's shared perforce depot. None of your local configurations choices alter the bytestream that exists on my computer in any way.</div>
<div>
<br /></div>
<div>
Of course aesthetics matter to programmers. But don't let that blind you to the reality that any aesthetic quality of your whitespace doesn't matter in the slightest to your compiler, continuous integration server, merge utility, source code repository, build server...</div>
<div>
<br /></div>
<div>
...and especially not to the users of your software.</div>
<div>
<br /></div>
<div>
My problem is that your subjective notions about aesthetics open the possibility for software defects to creep in.</div>
<div>
<br /></div>
<div>
To use a bad analogy:</div>
<div>
<br /></div>
<div>
<span style="font-size: large;"><span class="Apple-tab-span" style="white-space: pre;"> </span>You're trying to make the blueprints more pretty by drilling holes in the life raft.</span></div>
<div>
<span style="font-size: large;"><span class="Apple-tab-span" style="white-space: pre;"> </span>(The users won't notice the water coming in until it's too late.)</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<h3>
Appendix B: Some common objections (FAQ style)</h3>
</div>
<div>
<br /></div>
<div>
Q) Why don't we get a bunch of programmers, randomize formatting styles, and measure how long it takes them to identify software defects?</div>
<div>
A) Great idea! That's an excellent procedure for choosing presentation defaults for an IDE! On the other hand, when choosing a formatting style for transporting code between programmers, it makes more sense to use a style which is friendlier to automated tools and reduces the incidence of hidden software defects.</div>
<div>
<br /></div>
<div>
Q) Our ten million line code base already uses ABC style. Should we convert everything to QRS style?</div>
<div>
A) Are you crazy? Every change has a cost, consistency has value! Stick with ABC style!!!</div>
<div>
However, for any new code, and for any incremental changes you make to existing code, I strongly advise you to adopt the following two guidelines:<br />
<br />
<ul>
<li>Where braces are optional in your language ( if, while, do, ), make the usage of braces be mandatory.</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">int raii = 7; // Declare a single variable, initialize it once, (add an optional comment), all self-contained on one line.</span></li>
</ul>
</div>
<div>
<br /></div>
<div>
<br /></div>
</div>
missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com5tag:blogger.com,1999:blog-6140632138569689510.post-74456211840345847442014-12-14T00:10:00.002-08:002014-12-14T11:02:14.963-08:00Twenty years of Skidmarks<div style="line-height: 100%; margin-bottom: 0cm;">
Lately I've been digging through the old Skidmarks archives, and I came across this wee gem from 1993, no doubt written with lots of help from Simon:</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: 'Courier New', Courier, monospace;">Function.q hite {di.q,dj.q,oset.l}</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> UNLK a4</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> MOVE.l d2,a0</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> MOVE.l d1,d2:SWAP d2:EXT.l d2:ASL.l #7,d2:ADD.l d2,a0</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> MOVE.l d0,d2:SWAP d2:EXT.l d2:ASL.l #1,d2:ADD.l d2,a0</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"><br /></span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> MOVEM (a0)+,d2-d3 ;d0-d1 xy d2-d5 p0-p3</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> LEA 124(a0),a0:MOVEM (a0)+,d4-d5</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> MOVE d0,d6:MULU d1,d6:SWAP d6:MULU d6,d5 ; x. y.p3</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> NOT d0:MOVE d0,d6:MULU d1,d6:SWAP d6:MULU d6,d4 ;-x. y.p2</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> NOT d1:MOVE d0,d6:MULU d1,d6:SWAP d6:MULU d6,d2 ;-x.-y.p0</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> NOT d0: MULU d1,d0:SWAP d0:MULU d3,d0 ; x.-y.p1</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> ADD.l d2,d0:ADD.l d4,d0:ADD.l d5,d0 ;total</span></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;"> LSR.l#6,d0:RTS</span></span></div>
<div style="margin-bottom: 0cm;">
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><span style="line-height: 16px;">End Function</span></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="line-height: 100%;">For those not quite brave enough to decipher the 68000 assembly, here's what a strictly literal
translation might be:</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">float Height(float
x, float y, short *heightField){</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> //__asm{...}</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> heightField +=
int(x) * 64;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> heightField +=
int(y);</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> short height2 =
*heightfield++, height3 = *heightField++;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> heightField += 62;
short height4=*heightfield++, height5 = *heightField++;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float result5 =
frac( x) * frac( y) * height5;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float result4 =
frac(-x) * frac( y) * height4;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float result2 =
frac(-x) * frac(-y) * height2;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float result0 =
frac( x) * frac(-y) * height0;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float result = (result0 +
result2 + result4 + result5);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> return result / 64;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="line-height: 100%;">The motivation is that I've been working towards a new version for mobile devices, with a working title of "Super Skidmarks 2000" (hashtag #SS2K)</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
Here's what the modern version of that same function looks like, this time in C++ :</div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">float
SKTrack::GetHeight(float axisI,float axisJ)const{</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> int
fi=(int)floor(axisI);</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> int
fj=(int)floor(axisJ);</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> if(fi<0||fi>=63){</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> return 0.0f;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> if(fj<0||fj>=63){</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> return 0.0f;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> int index=fi+fj*64;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float
v0=HeightField[index];</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float
v1=HeightField[index+1];</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float
v2=HeightField[index+64];</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float
v3=HeightField[index+65];</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float
s=axisI-floor(axisI);</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float
t=axisJ-floor(axisJ);</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float
v01=v0*(1.0f-s)+v1*s;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float
v23=v2*(1.0f-s)+v3*s;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"><br />
</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> float
height=v01*(1.0f-t)+v23*t;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;"> return height;</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div style="line-height: 100%; margin-bottom: 0cm;">
<br /></div>
<br />
<div style="line-height: 100%; margin-bottom: 0cm;">
<span style="line-height: 100%;">As always, any questions / comments, or suggestion for a better name etc, please leave a comment below!</span></div>
missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com2tag:blogger.com,1999:blog-6140632138569689510.post-40721009714090211112014-11-29T11:50:00.000-08:002014-12-01T00:51:10.819-08:00Why he vertically aligns his code (And why you shouldn't)Over on Terence Eden's blog, the latest post is about vertically aligning code : <a href="https://shkspr.mobi/blog/2014/11/why-i-vertically-align-my-code-and-you-should-too">https://shkspr.mobi/blog/2014/11/why-i-vertically-align-my-code-and-you-should-too</a><br />
<br />
The "bad" example looks like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiluZ-wpBFW2TUuIfC-Rxr6QYWGfVPXdGpmMc4t89gLtYJ6yj3B4BY6R0VNKBidsRSAAA8UEv_TrcyJYUtCxKce8jzf1O_1-ao5TMFhWpAAZrwwiRrVNWGSX_DGAQbHNlDY1sfj7_fdLtk/s1600/Screen+Shot+2014-11-30+at+8.31.39+am.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiluZ-wpBFW2TUuIfC-Rxr6QYWGfVPXdGpmMc4t89gLtYJ6yj3B4BY6R0VNKBidsRSAAA8UEv_TrcyJYUtCxKce8jzf1O_1-ao5TMFhWpAAZrwwiRrVNWGSX_DGAQbHNlDY1sfj7_fdLtk/s1600/Screen+Shot+2014-11-30+at+8.31.39+am.png" height="80" width="320" /></a></div>
<br />
Which is then "fixed" to make it look like this :<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8QAoHQh5hV_RptrfkDEBWctdr68Mt4Bll3H8P63XRVwbA0xZNBUAEkyB0laYcaoeWSfjSAv-7Sluu19aAezdcKS5Zf70qBz3Y1qNfBqMyze4H0WFZOqKscHkpPaOCb1gqT10VFcZmJiM/s1600/Screen+Shot+2014-11-30+at+8.32.58+am.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8QAoHQh5hV_RptrfkDEBWctdr68Mt4Bll3H8P63XRVwbA0xZNBUAEkyB0laYcaoeWSfjSAv-7Sluu19aAezdcKS5Zf70qBz3Y1qNfBqMyze4H0WFZOqKscHkpPaOCb1gqT10VFcZmJiM/s1600/Screen+Shot+2014-11-30+at+8.32.58+am.png" height="79" width="320" /></a></div>
<br />
<br />
Just for comparison, I typed it into my regular text editor:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLFKhv-do7nb8EMCXlI6mpBO_v_z3zC8zXO_abgFmbgqrWc1TcDad18DdEoLF_nwBxtmr3z2a2-dp8H3oqtxHgmZ-BM6yuOLoE1E1Fyx-toqvoVgUu6L6ljkpSx7lXtOx1baNl2rh9S1g/s1600/Screen+Shot+2014-11-30+at+8.25.26+am.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLFKhv-do7nb8EMCXlI6mpBO_v_z3zC8zXO_abgFmbgqrWc1TcDad18DdEoLF_nwBxtmr3z2a2-dp8H3oqtxHgmZ-BM6yuOLoE1E1Fyx-toqvoVgUu6L6ljkpSx7lXtOx1baNl2rh9S1g/s1600/Screen+Shot+2014-11-30+at+8.25.26+am.png" height="115" width="320" /></a></div>
<br />
The point being, because I'm using a well designed syntax highlighting where the numbers (green) contrast with the operators. If you so choose, you can visually inspect just the green numbers and just as easily spot the outlier.<br />
<br />
<i>(Pro-tip: To concentrate on just one color, defocus your eyes slightly by staring "through" the plane of the monitor to engage your eye's <a href="http://en.wikipedia.org/wiki/Cone_cell">cone cells</a>. With a little practice, you'll find yourself doing this automatically when you want to focus on the structure of the code instead of the details. For best results, you might need to make the glyphs larger on screen....)</i><br />
<div>
<br /></div>
Note too, how the combination of proportional font and camelCase instead of under_scores keep the code density onscreen the same, but the individual glyphs appear larger in-place.<br />
<br />
My code editor also uses syntax highlighting to hint the kerning. So for example, the kerning around the equals sign and the semi-colon are particularly loose to aid in their recognition. Similarly, the single space character (' ') has a width 50% larger than would be used for normal paragraph text.<br />
<br />
But here's the big change that Terence missed, I've sorted all the variable declarations alphabetically to ensure there are no duplicates. This is a zero-cost policy that can simplify merges and conflict resolution when multiple variables (possibly duplicate) have been added upstream.<br />
<br />
<h3>
Coding Atoms</h3>
The bigger problem is the coding atom is the line-of-code.<br />
<br />
Lets take another code example from Terence's blog post, this time a function declaration :<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">extern int SomeDemoCode(int fred,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> int wilma);</span><br />
<br />
That's an atom right there - you can't split that up without changing its meaning. Watch what happens if I try to add a parameter in an excess white-space environment:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">extern int SomeDemoCode(int fred,</span><br />
<span style="font-family: Courier New, Courier, monospace;">+ int barney,</span><br />
<div>
<span style="font-family: 'Courier New', Courier, monospace;"> int wilma);</span></div>
<div>
<br /></div>
The diff splits our (atomic) function signature across 3 lines, exposing us to problems where a <span style="font-family: Courier New, Courier, monospace;">git merge</span> might accidentally succeed, when really we need it to flag a merge conflict.<br />
<br />
(For a real world case of how bad automatic merging can be, take a look at the <a href="https://www.imperialviolet.org/2014/02/22/applebug.html">Goto Fail Bug</a>)<br />
<br />
Now compare if everything had been on the same line, the diff would look like :<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">-extern int SomeDemoCode(int fred, int wilma);</span><br />
<span style="font-family: Courier New, Courier, monospace;">+</span><span style="font-family: 'Courier New', Courier, monospace;">extern int SomeDemoCode(int fred, </span><span style="font-family: 'Courier New', Courier, monospace;">int barney, </span><span style="font-family: 'Courier New', Courier, monospace;">int wilma);</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span>
<br />
TL;DR: Using whitespace to control your code presentation is a hack from the '70s.. get a better editor.<br />
<br />
p.s. Some formatting edits have been made to make this post clearer.missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com19tag:blogger.com,1999:blog-6140632138569689510.post-91766028082409000942014-09-12T23:27:00.000-07:002015-12-13T20:46:20.967-08:00Wi-Fi in SchoolsA friend of mine asks :<br />
<br />
<a href="http://commons.wikimedia.org/wiki/File%3AOLPC_Class_-_Mongolia_Ulaanbaatar.JPG" title="By OLPC [CC-BY-2.5 (http://creativecommons.org/licenses/by/2.5)], via Wikimedia Commons"><img align="right" alt="OLPC Class - Mongolia Ulaanbaatar" src="//upload.wikimedia.org/wikipedia/commons/3/37/OLPC_Class_-_Mongolia_Ulaanbaatar.JPG" width="300" /></a><br />
<span style="font-family: "verdana" , sans-serif; font-size: large;">Question : <span style="color: blue;">What's the effect on the human body, of 20 children in a classroom, each downloading a 3 minute youtube video over Wi-Fi?</span></span><br />
<br />
<h3>
An excellent question!</h3>
<br />
As with all good science, let's start with an experiment. I happen to have a 3 minute HD video on my network, so I can time how long it takes to copy across to my laptop:<br />
<br />
<blockquote>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">missingbytes:$ time copy /NetworkDrive/HDVideo.mp4 .</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">real 0m<b>6.550s</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">user 0m0.001s</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">sys 0m0.116s</span></blockquote>
<br />
So a single 3 minute video (3:19 to be precise) will use about 6.5 seconds of Wi-Fi time to copy.<br />
<br />
With 20 students, and rounding up a little to account for congestion..<br />
<br />
<i>... lets call it 200 seconds of Wi-Fi activity total.</i><br />
<br />
<h3>
Transmit power</h3>
The transmission power for Wi-Fi signals is heavily regulated in the EU, the US and also in New Zealand where I'm performing the test.<br />
<br />
The maximum 2.4-GHz transmission power is regulated by law, so lets assume it's <b>20dBm = 100mW = 0.1W </b>( <a href="http://en.wikipedia.org/wiki/DBm">source</a> )<br />
<br />
As we all learnt when we were in school, a watt is a joule per second, so <b><a href="http://www.wolframalpha.com/input/?i=200+seconds+at+0.1W">200 seconds at 0.1W</a> </b>is 20J.<br />
<br />
Now we know that a class room of children downloading a youtube video results in 20 joules of microwave energy being emitted from the Wi-Fi router's antenna.<br />
<br />
<blockquote>
<h3>
A brief diversion : Ionizing and Non-Ionizing radiation</h3>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvvi08wdQVpuDpOnEp-SNEwCpJH1hT4mA0ZRhrYKljzCmWRx1PRTtVVUvPj1luNFffjjdytA-qPKyO1qyGcvq5nT7bte-CfAOtNf7K6Io77y1VDILpVf-q5ni09M-cv2zfe_QhW3zORDw/s1600/Rainbow.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvvi08wdQVpuDpOnEp-SNEwCpJH1hT4mA0ZRhrYKljzCmWRx1PRTtVVUvPj1luNFffjjdytA-qPKyO1qyGcvq5nT7bte-CfAOtNf7K6Io77y1VDILpVf-q5ni09M-cv2zfe_QhW3zORDw/s320/Rainbow.jpg" width="320" /></a></div>
Electromagnetic radiation forms a <a href="http://en.wikipedia.org/wiki/Electromagnetic_spectrum">spectrum</a>, from low frequency and radio waves, up through the microwaves, visible light, X-rays and on to gamma rays which have very high frequencies indeed.<br />
<br />
Those high frequencies are characterized as <b>ionizing</b>, they're very dangerous to humans and their ability to cause DNA damage and ultimately cancer is well known. This is the reason why we need to be so careful around medical/dental imaging devices, and need to take precautions such as wearing sunscreen and polarized sunglasses when we're outdoors on a sunny day.<br />
<br />
It's not necessarily the amount of energy, it's more the frequency that's the problem. This high frequency ionizing radiation quite literally has the ability to rip electrons off their atoms. It's these "<a href="http://en.wikipedia.org/wiki/Ion">ions</a>" which go on to cause damage to biological systems.<br />
<br />
By contrast, the lower frequency <b>non-ionizing</b> radiation (such as used in Wi-Fi, or FM radio) doesn't have the same ability to affect us in this way.<br />
<br />
By itself, non-ionizing radiation can only cause <i>heating </i>in biological systems. Indirectly, it's this heating which slows down or speeds up chemical reactions and/or signalling within the cell, and it's these secondary effects which has the potential to cause problems.<br />
<br />
Intuitively, this is why the 1000 watt microwave oven in your kitchen makes food super hot in a few minutes using microwave energy, but it doesn't actually make your food radioactive. (You'd need an X-Ray oven for that!)<br />
<br />
Anyway, lets continue, we've got 20 joules remember?</blockquote>
<br />
<h3>
Absorption</h3>
<br />
Now we need to make a pretty unrealistic assumption. Suppose that the entirety of those 20 joules of energy was somehow absorbed by one child. Of course, this can't happen in the real world for two fairly obvious reasons:<br />
<br />
<ul>
<li>A router transmits energy in all directions. For all the energy to be absorbed by the child, the router would somehow need to be <b>inside</b> the child.</li>
<li>Microwave energy interacts only weakly with the human body. That's one of the great benefits of Wi-Fi, it can pass right through walls and ceilings and straight through you and me.</li>
</ul>
<br />
But just for fun, lets continue on anyway and figure out what would happen if all of those 20 joules were absorbed by one child.<br />
<br />
An average 6 year old child weighs about 22 kilograms. <b>(Of course, my 4 year old son also weighs 22 kilograms, but that's a blogpost for another day!)</b><br />
The human body is about 65% water, so lets consider 14 kilograms of water.<br />
<br />
The specific heat capacity of water is <a href="http://www.wolframalpha.com/input/?i=specific+heat+capacity+of+water">4.18 J / gK</a><br />
<br />
So we have 20 J / (14,000 g) / (4.18 J / gK) = 0.00034 K = 0.0004 °C<br />
(That's 0.4 millikelvin for all you geeks out there.)<br />
<br />
<h3>
Answers!</h3>
So there we have it, even with a wildly exaggerated assumption:<br />
<span style="font-family: "verdana" , sans-serif;"><br />
</span> <span style="font-family: "verdana" , sans-serif; font-size: large;">Answer : <span style="color: blue;">A classroom of children, all downloading a 3 minute youtube clip over Wi-Fi yields a maximum biological heating due to 2.4GHz microwave radiation of 0.0004 °C.</span></span><br />
<br />
(0.4 millikelvin is about twice as small as it's possible to measure using a precision thermometer.)<br />
<br />
<h3>
Conclusion</h3>
<br />
We shouldn't really be too surprised. Wi-Fi signals are incredibly weak. Consider this, those 20 joules of microwave radiation is the same amount of chemical energy contained in one thousandth of a teaspoon of sugar.<br />
<br />
There's no way to <i>prove scientifically </i>that microwave radiation from Wi-Fi is safe in the human body. Science doesn't work that way. <a href="http://en.wikipedia.org/wiki/Russell%27s_teapot">You can't prove a negative.</a><br />
<br />
But we can try and make smart choices about tiny risks.<br />
<img align="right" src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Bananas_white_background.jpg/320px-Bananas_white_background.jpg" /><br />
<br />
For example, the <a href="http://en.wikipedia.org/wiki/Banana_equivalent_dose">exposure from a banana is about 0.1 μSv of harmful ionizing radiation </a>because of their high quantities of naturally occurring <a href="http://en.wikipedia.org/wiki/Potassium-40">radioactive potassium</a>.<br />
<br />
Yet who thinks twice about giving bananas to kids in schools?<br />
<br />
Thoughts, questions or especially corrections? Please feel free to leave a comment down below!missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-434502985279716452013-11-07T00:16:00.000-08:002013-11-07T14:57:35.551-08:00ScooterBoy Global LaunchModka Games is very proud to launch ScooterBoy:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKyvaA-pqGiDY67AsPDEtwCkhziX5su4WMavXYkWngJaSCKS3zlVErEm9uR-cKWq4WJlzEGyrfrJyNXi1yBZpmeH7jz3YPhZiQXrvMH1GNRyOemvtZXkduTjW0UYaCOn6_xf44m9vEcoA/s1600/ScooterBoy+Global+Launch.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKyvaA-pqGiDY67AsPDEtwCkhziX5su4WMavXYkWngJaSCKS3zlVErEm9uR-cKWq4WJlzEGyrfrJyNXi1yBZpmeH7jz3YPhZiQXrvMH1GNRyOemvtZXkduTjW0UYaCOn6_xf44m9vEcoA/s400/ScooterBoy+Global+Launch.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">ScooterBoy, free on the App Store, for iPhone, iPod touch and iPad</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY01KxMV4jkUshTLqbQvxFS8DFt1rVsO8NdNulmD3xLyZOJnSH-SvqZJWKNbwW08BPlqNWIUDKgH6nUXzEWFaoixbHQxM31-qX7POnKUaqVDjmpdBFn4Esyer3xljO1qLex4apnjjB_QY/s1600/ScooterBoyHiRes.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="201" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY01KxMV4jkUshTLqbQvxFS8DFt1rVsO8NdNulmD3xLyZOJnSH-SvqZJWKNbwW08BPlqNWIUDKgH6nUXzEWFaoixbHQxM31-qX7POnKUaqVDjmpdBFn4Esyer3xljO1qLex4apnjjB_QY/s400/ScooterBoyHiRes.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">ScooterBoy HD screenshot (click for full res)</td></tr>
</tbody></table>
<br />
<br />
<h3>
Gameplay First</h3>
ScooterBoy brings back the classic feel of the arcade, updated with one button touch controls. Of course you can jump and dodge to avoid obstacles, but in ScooterBoy you also swipe to change lanes, drop-boost to go faster, and there's loads of power ups and pickups to collect too.<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicamMPCpCTAZaD2whzMvuEoiN4dMVOncJcMqNIC8ULmrQFOavwYBVBqilHxjDLviSSzaUKUEbqElxahQYJ01QhQ7hhs7GkKpFoav4YcOIm8kZXF2FOKJjRdWebu-zvHuKoT43Y9YliQJY/s1600/ScooterKing.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="277" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicamMPCpCTAZaD2whzMvuEoiN4dMVOncJcMqNIC8ULmrQFOavwYBVBqilHxjDLviSSzaUKUEbqElxahQYJ01QhQ7hhs7GkKpFoav4YcOIm8kZXF2FOKJjRdWebu-zvHuKoT43Y9YliQJY/s400/ScooterKing.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">"Scooter Boy!"</td></tr>
</tbody></table>
<br />
<h3>
<span style="font-size: small; font-weight: normal;">If you want to climb the high score ladder, you'll need to learn the mushroom's secrets. Or you can simply relax and explore ScooterBoy's amazing world at your own pace.</span></h3>
<div>
<span style="font-size: small; font-weight: normal;"><br />
</span></div>
<h3>
Upgrades</h3>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirQy4mM9SOM1t3rEbG7RLsP2aQmhJlJ3I54CO5uz-8A9JTU0C_F9f2X2i_hFSlo5Yhk6YIZCTtxA4_DSFFqb10ud_VrsqZnm1gie3gHjoIXZ8CD0M6Qd5VraNKRPvfmjgpLBmCYazgrIs/s1600/jump-the-shark.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirQy4mM9SOM1t3rEbG7RLsP2aQmhJlJ3I54CO5uz-8A9JTU0C_F9f2X2i_hFSlo5Yhk6YIZCTtxA4_DSFFqb10ud_VrsqZnm1gie3gHjoIXZ8CD0M6Qd5VraNKRPvfmjgpLBmCYazgrIs/s400/jump-the-shark.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Marmot, jumping with the shark.</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
Upgrade your scooter, choose new characters, hats, wheels and more..</div>
<div>
<br /></div>
<h3>
Buy a friend!</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVCgD3-WbCKgPD3DddSOY7pV3dRlP9f8bMKoi-KqF0Zs2f9jJyxSukWeVa7o3ezzgrjWoRZpRGQqehtr7mWL_2KcdD5zIKOfNuK7-pQFsS8Juoe7vxK5-YgAIQlLFxEaTq6aVD8Pt6dJY/s1600/ScooterBoyPets.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVCgD3-WbCKgPD3DddSOY7pV3dRlP9f8bMKoi-KqF0Zs2f9jJyxSukWeVa7o3ezzgrjWoRZpRGQqehtr7mWL_2KcdD5zIKOfNuK7-pQFsS8Juoe7vxK5-YgAIQlLFxEaTq6aVD8Pt6dJY/s400/ScooterBoyPets.jpg" width="400" /></a></div>
<br />
<br />
Need a little something extra? Why not buy a Pet from the store? These cute little helpers will fly along and collect coins and points to boost your score. You can even flick your pet to reach up even higher.<br />
<br />
<br />
<h3>
PhotoBooth</h3>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0Vs7mJrxAHO6rsdBoTQ6ApgdsN-c8euuzYTBx_j7ZmXdTL6Z7jxBz0SwoZ06zyxES8wdXS-BLs3Td033Utnrf9s__pWUDEZN8jYKo0B2CyfV4HOluE9csoTlZOxNUZiGhHWcodTb9s8E/s1600/ScooterBoy-PhotoBooth.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0Vs7mJrxAHO6rsdBoTQ6ApgdsN-c8euuzYTBx_j7ZmXdTL6Z7jxBz0SwoZ06zyxES8wdXS-BLs3Td033Utnrf9s__pWUDEZN8jYKo0B2CyfV4HOluE9csoTlZOxNUZiGhHWcodTb9s8E/s320/ScooterBoy-PhotoBooth.JPG" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Bizzer in the PhotoBooth with his dragonfly.</td></tr>
</tbody></table>
<div>
<br /></div>
<br />
Meanwhile, in the PhotoBooth:<br />
<br />
<ol>
<li>Choose a background and a frame.</li>
<li>Take a photo of <b>your</b> ScooterBoy.</li>
<li>Share with your friends.</li>
<li>Repeat!</li>
</ol>
<br />
<br />
<br />
<h3>
Music</h3>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4q-2i1yGpz17otaJmtoKVgifTc4WFt08zLr_QZ24npCrG2TFbFEedMF3sEQS2z3qsFUHhJly8CE1UwR7muEXShxkBfRplooU3EnuD-wlvYICDd0rxnU3QcVRo04gcwhESECbplFCNtYw/s1600/QRCode+-+www.scooterboygame.com.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4q-2i1yGpz17otaJmtoKVgifTc4WFt08zLr_QZ24npCrG2TFbFEedMF3sEQS2z3qsFUHhJly8CE1UwR7muEXShxkBfRplooU3EnuD-wlvYICDd0rxnU3QcVRo04gcwhESECbplFCNtYw/s200/QRCode+-+www.scooterboygame.com.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Download link for ScooterBoy</td></tr>
</tbody></table>
<div>
Did I mention the music? ScooterBoy has nearly an hour of classic recordings from the 50s and 60s</div>
<h3>
<br />
</h3>
<div>
<br /></div>
<div>
<br /></div>
<h3>
<br />
</h3>
<div>
<br /></div>
<h3>
Download, for free!</h3>
And the best part, ScooterBoy is free to download, and free to play!<br />
<br />
So what are you waiting for?<br />
<br />
<span style="font-size: x-large;"><a href="https://itunes.apple.com/us/app/scooter-boy/id581794421">Download ScooterBoy Now!</a></span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZbKMzDa6RcYpCskmBs7fUA9OHmYvmYV7jMWPVwE2zBEpYA2S9HYeh20vPKe-qlbxgm7pFvbOYTRqIY0cjXoP3g94zO-7IVt_ZbnKPjxOXjZ7Cm9ixSv0V7RwvnfnIK-Vpz4uOBaooHdA/s1600/Icon+-+ScooterBoy+%28HiRes%29.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZbKMzDa6RcYpCskmBs7fUA9OHmYvmYV7jMWPVwE2zBEpYA2S9HYeh20vPKe-qlbxgm7pFvbOYTRqIY0cjXoP3g94zO-7IVt_ZbnKPjxOXjZ7Cm9ixSv0V7RwvnfnIK-Vpz4uOBaooHdA/s320/Icon+-+ScooterBoy+%28HiRes%29.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com2tag:blogger.com,1999:blog-6140632138569689510.post-59514516065958183182013-10-19T13:51:00.000-07:002013-10-21T01:07:41.371-07:00Praise the Fire Fighter, Damn the Safety InspectorThere's a sickness eating our industry. It's a culture of Macho Programming. In it's simplest form, it's the idea that if we just push harder, longer, stronger, then we will win. Yet time and time again, experience shows that the way to win is by working smarter.<br />
<br />
<h3>
Side-effects</h3>
I was once working on a particular AAA title. The game was running late. We were in crunch, and had been for a while. There was no end in sight. I came across the following code:<span style="font-size: 13px;"><sup>(1)</sup></span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">bool DetectCollision(Vector3 location, float radius){</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ...</span><br />
<span style="background-color: yellow; font-family: Courier New, Courier, monospace;"> radius * 1.2f;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ...</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<br />
So that line of code makes the collisions a bit fatter. It's what we call a 'Fudge Factor' - we don't know <b>why </b>a problem is occurring, so we fudge the numbers a little until it works.<br />
<br />
But take a closer look. The statement as written has no side-effects. It doesn't actually modify the value of radius. When the programmer wrote:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;"> radius * 1.2f;</span><br />
<br />
they <i>intended</i> to write:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;"> radius </span><span style="background-color: yellow; font-family: 'Courier New', Courier, monospace;">*=</span><span style="font-family: 'Courier New', Courier, monospace;"> 1.2f;</span><br />
<br />
Let's review the facts:<br />
<br />
<ul>
<li>It's the wrong fix to begin with (fudge factors are generally a bad idea)</li>
</ul>
<ul>
<li>It doesn't actually change the behaviour of the running program</li>
</ul>
<ul>
<li>The programmer didn't verify that their "fix" worked</li>
</ul>
<br />
And we can safely assume that the programmer didn't verify the original bug in the first place.<br />
<br />
<h3>
Compound Fail</h3>
It gets worse. In this late stage of crunch, there were so many easily avoidable bugs coming in to the code, that the production team mandated every changelist required a second programmer to sign off.<br />
<br />
That's right, not one, but two programmers, working together, managed to convince each other that this placebo changelist actually improved the game. Together, they marked the bug as fixed and sent it back to QA, fully confident they had made the game better.<br />
<br />
What other trivial mistakes did those programmers make that night?<br />
<br />
What a colossal waste of time and resources, simply because those two programmers had inadequate sleep. The project would have been much better off if those two programmers had just gone home at 18:00. Or 17:00. Or even 14:00.<br />
<br />
<span style="font-size: x-small;"><i>[Edit: I just wanted to add, these are actually two really good programmers! I'd jump at the chance to have them on my team again. The equation here is </i><span style="font-family: Courier New, Courier, monospace;">crunch + good programmers = too many careless mistakes.</span><i>]</i></span><br />
<br />
<h3>
Praise The Fire Fighter ...</h3>
When you're deep in crunch, it's easy to see the heroic efforts, the mountains of caffeinated beverages, the change logs at 4am. It's easy to point to the person who's working the hardest and say "We all need to be more like that guy." Because when it's all falling apart, you need to do <b>something</b>.<br />
<div style="text-align: right;">
<span style="font-size: x-small;">(Hint: That <b>something</b> we need to do is to get more sleep.)</span></div>
<div style="text-align: right;">
<br /></div>
<h3>
... Damn the Safety Inspector</h3>
And when you're at the beginning of the project, and the Safety Inspector is telling you that what you're building isn't up to code, that the schedules are unrealistic and will lead to crunch, slipped deadlines, hard-to-find bugs and adds unacceptable levels of risk to the project... Well they're easy to dismiss "We're trying to build something here! Why are you trying to stop us?"<br />
<div style="text-align: right;">
<span style="font-size: x-small;">(Hint: The Safety Inspector is probably right.)</span></div>
<div style="text-align: right;">
<br /></div>
<h3>
Macho Programming</h3>
As an industry, we should be working smarter than that. We should be rewarding measurable results and hard evidence, rather than effort and posturing.<br />
<br />
To me, Macho Programming, is blundering onward in whichever way you possibly can, without regard to what's best for the project or the team, simply for the appearance of getting something done.<br />
<br />
I think we can do better than that. In the true Agile sense, as a team, we need to make the best decisions based on the best information we have, right now, and move forward in the best direction we can.<br />
<br />
Who's with me?<br />
<br />
<br />
<br />
<br />
<span style="font-size: x-small;"><sup>(1)</sup> Some details have been changed to preserve anonymity.</span>missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-60009130771739401312013-09-30T19:02:00.001-07:002013-10-01T13:30:29.498-07:00ScooterBoy NZ Launch at Digital Nationz<span id="goog_660697462"></span><span id="goog_660697463"></span><br />
ScooterBoy and Modka Games was lucky enough to be involved with the Homegrown exhibit at the <a href="http://digitalnationz.com/" target="_blank">Digital Nationz</a> expo!<br />
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiY3wGN7ctVlUFQ2UVmKMs-tPCWqxqbKvPUjZ3NDH9QJaOvkp2WQFvUfD3MXSpGB7AZJUJdK_b_OnWEyh0f89qWafHm4zM-wxVsfeCvnpqX6lpmxItAHghyphenhyphen19fWxbWTH8TGCEx7B8jrLo/s1600/Pic1.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="265" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiY3wGN7ctVlUFQ2UVmKMs-tPCWqxqbKvPUjZ3NDH9QJaOvkp2WQFvUfD3MXSpGB7AZJUJdK_b_OnWEyh0f89qWafHm4zM-wxVsfeCvnpqX6lpmxItAHghyphenhyphen19fWxbWTH8TGCEx7B8jrLo/s400/Pic1.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The ScooterBoy booth at Digital Nationz</td></tr>
</tbody></table>
<h3>
Hands on</h3>
Our booth consisted of a large monitor hooked up to a laptop (Display Mirror), playing the actual game. We had a second laptop with a slideshow, and then lots of glossy printouts of the logo, icon and artwork.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV5JobB_Uyj5Nwq_wNOrR71xsHsy7RbkmIED_dSoA7dmgOlh7Gd98szyeetr8YHaGLZOxPxV8aNMumnxcLTwNoiCg6s8lfpUo_GJWKyfPCYxMTzUrxyGZS3TNEPacFP0BGpWP1V-bEylo/s1600/QRCode+-+www.scooterboygame.com.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV5JobB_Uyj5Nwq_wNOrR71xsHsy7RbkmIED_dSoA7dmgOlh7Gd98szyeetr8YHaGLZOxPxV8aNMumnxcLTwNoiCg6s8lfpUo_GJWKyfPCYxMTzUrxyGZS3TNEPacFP0BGpWP1V-bEylo/s200/QRCode+-+www.scooterboygame.com.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><a href="http://www.blogger.com/www.scooterboygame.com">www.scooterboygame.com</a></td></tr>
</tbody></table>
We also had two iPads running the game, which we tried to get into the hands of as many players as possible, getting some awesome user feedback.<br />
<br />
Oh, and a portable "QR" code with a direct download link for iPhone users!<br />
<br />
<h3>
Attract Mode</h3>
<br />
For the main screen, we cooked up a special build of ScooterBoy running in "Attract mode" - basically bouncing between the intro comic, level selection, and the game itself, choosing random levels, scooters, characters, pets, music, etc.<br />
<br />
I hooked up Momma's AI to the player, so the game would merrily play itself with no human intervention required.<br />
<br />
"Attract Mode" turned out to be a super useful feature, it meant we could talk to gamers 1 on 1, while the screen continued to play for the small crowd that gathered.<br />
<br />
... in fact "Attract Mode" proved to be so useful, that on the second day of the expo, two other Indies had added the feature to their game!<br />
<br />
<h3>
Big Screen</h3>
<br />
ScooterBoy also got some time on this awesome 103" panel upstairs in the chill out zone. It really shows off the amazing HD retina graphics in ScooterBoy!<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq26EyW8LE5Kx_PvrgM81f0GReBRmaqKLIpxLdZ6m51SKiJ7_NE36-jAd_xJLIElBPquMOzf5eZdTGnJMZJ1C0jZNZ7xJQyoPrfrseYumbCMN4JiPvhFBNdEg4eHH5DGL-3DnCStvlsqY/s1600/Pic2.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="265" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjq26EyW8LE5Kx_PvrgM81f0GReBRmaqKLIpxLdZ6m51SKiJ7_NE36-jAd_xJLIElBPquMOzf5eZdTGnJMZJ1C0jZNZ7xJQyoPrfrseYumbCMN4JiPvhFBNdEg4eHH5DGL-3DnCStvlsqY/s400/Pic2.jpg" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Telecom Homegrown "BigScreen", running ScooterBoy</td></tr>
</tbody></table>
<br />
<h3>
Thanks!</h3>
Thanks everyone for making an awesome <a href="https://twitter.com/search?q=%23ScooterBoyGame" target="_blank">#ScooterBoyGame</a> weekend with @DIGITALNATIONZ<br />
<br />
And a special shoutout of thanks to Telecom, Asus, @oldjackgrey, @BenTuhoeKenobi and @sknightly!!<br />
<br />
<h3>
Shameless Plug</h3>
And if you're in New Zealand, and own an iPhone, iPad or iPod touch, why not download ScooterBoy and give us a rating! <a href="https://itunes.apple.com/nz/app/scooter-boy/id581794421" target="_blank">ScooterBoy on NZ App Store</a>missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-51668363578871738562013-09-19T12:11:00.000-07:002013-09-19T12:11:21.863-07:00Random<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVX5KjaNjHSJo5I2105YHaPM20DdnaaBBJ1DEd66y7k-oCtXYYefqbOstkj0f9zvheYKSUI5rBH_dMobtuXgj09XD1LXfUz8ErZTjhutDMsgu4ReXDPuntIGLzzG_LxbgyogQOVmlHVwA/s1600/Shot002.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVX5KjaNjHSJo5I2105YHaPM20DdnaaBBJ1DEd66y7k-oCtXYYefqbOstkj0f9zvheYKSUI5rBH_dMobtuXgj09XD1LXfUz8ErZTjhutDMsgu4ReXDPuntIGLzzG_LxbgyogQOVmlHVwA/s320/Shot002.jpg" width="320" /></a></div>
Lately, I've been tuning the "Drop-Rate" of pickups in <a href="http://scooterboygame.com/" target="_blank">Scooter Boy</a>. It's actually a lot like handing out candy at Halloween.<br />
<br />
Allow me to use this handy diagram to explain:<br />
<br />
<table border="2"><tbody>
<tr><td><div style="text-align: center;">
Too little Candy</div>
</td><td><div style="text-align: center;">
Too much Candy</div>
</td></tr>
<tr><td>Not enough candy to go 'round - some people walk away empty handed.</td><td>Everyone is all full of sugary goodness, and they don't want any more.</td></tr>
</tbody></table>
<br />
But that's not actually what I wanted to talk about today.<br />
<br />
I wanted to talk about Pigeons.<br />
<br />
<h3>
The Pigeon Food Dance</h3>
There was a famous set of experiments back in the '30s that revolved around withholding <strike>candy</strike>food from pigeons. In one of these experiments, the amount of time between successive drops was random. It turns out that each of the pigeons developed a (unique) ritualistic food dance. In happy pigeon land, it was the completion of the dance which <i>caused</i> the food to appear.<br />
<br />
Now the curious thing was, the time it took for the pigeon to complete the dance was slightly longer than the <i>average</i> time between drops.<br />
<br />
So when the pigeon completed the dance, there was a better than 50/50 chance of getting food. And if not, well repeating the dance a second time would surely do it!<br />
<br />
<div style="text-align: right;">
<span style="font-size: xx-small;">(Have you ever timed how long it takes to reboot your computer when you've got Tech Support on the phone?) </span></div>
<h3>
</h3>
<h3>
Random Drop Rates</h3>
For most of Scooter Boy's development, I've been using <b>random </b>drop rates. Power ups would appear, seemingly at random. Sometimes you'd get lots, and sometimes you'd go ages without seeing any.<br />
<br />
Worse still, changing the drop rate, by changing the percentage of a drop, was very clumsy. You'd double or quadruple the drop rate, play the game, and the results would be... well ... random... There was no way to tell if your change was making the game better.<br />
<br />
In short, random drops, just aren't <a href="http://missingbytes.blogspot.com/2012/07/finding-fun.html" target="_blank">fun</a>!<br />
<br />
<h3>
A Drop Rate Schedule</h3>
I'm in the process of changing all those drop-rate percentages into times. 30±10 seconds between drops. Or 120±60. It's so much more <i>measurable</i>. And it turns out, it's a lot more fun too. As a player, it feels like the powerups are rewarding your effort.<br />
<br />
So down with Mathematical Randomness! Lets make the game match the player's expectations. Lets <a href="http://missingbytes.blogspot.com/2012/07/i-make-video-games.html" target="_blank">put the fun first</a>!missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-87821803244278877382013-08-28T20:39:00.001-07:002013-08-28T22:25:49.158-07:00Analytics<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitN629U6kJ535eEaZXqIqvceTC9IokxyPv_LORbhaMMHZvOJDYaz9VpUkh0cpvNDGlwky1e5wO0LkLIfxCKwZ1BNJSDqsUApaaP9DqKYWboakzL0PbGR3s5z7TtcH0PHBer2gsDjCJ0ag/s1600/ScooterBoy_Coming_Soon.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitN629U6kJ535eEaZXqIqvceTC9IokxyPv_LORbhaMMHZvOJDYaz9VpUkh0cpvNDGlwky1e5wO0LkLIfxCKwZ1BNJSDqsUApaaP9DqKYWboakzL0PbGR3s5z7TtcH0PHBer2gsDjCJ0ag/s640/ScooterBoy_Coming_Soon.jpg" width="250" /></a></div>
If you happen to live in a certain North European Country, in the wee hours of this morning, <a href="http://scooterboygame.com/" target="_blank">ScooterBoy </a>went live!!<br />
<br />
That's right, you can now <a href="https://itunes.apple.com/se/app/scooter-boy/id581794421" target="_blank">download ScooterBoy</a>, for free!! <span style="font-size: xx-small;">(with certain geographical restrictions.)</span><br />
<br />
"But why can't I download it??!" I hear you ask.<br />
<br />
Well, you see, it works like this :<br />
<br />
We want to make the best release possible in the largest market.<br />
<br />
<span style="background-color: white; color: #444444; font-family: arial, sans-serif; font-size: x-small; line-height: 16px;">➡</span><span style="background-color: white; color: #444444; font-family: arial, sans-serif; font-size: x-small; line-height: 16px;"> </span> The best way to do that is to use feedback from real live customers to improve the game.<br />
<br />
<span style="background-color: white; color: #444444; font-family: arial, sans-serif; font-size: x-small; line-height: 16px;"> ➡</span><span style="background-color: white; color: #444444; font-family: arial, sans-serif; font-size: x-small; line-height: 16px;"> </span> Where best to get those customers? Yes! From a certain Northern European Country!<br />
<br />
<h3>
Analytics</h3>
Now our analytics takes over. How many downloads will we get? How long will players play? Which level and characters do they play the most? How quickly do they earn currency? What's their favorite IAP (In-App Purchase). What does our retention look like? Where does the game crash?<br />
<br />
We can turn all these questions into metrics, then apply those metrics to our game.<br />
<br />
We will compare our numbers to our expectations, and then see which numbers we want to improve.<br />
<br />
<h3>
What If?</h3>
The next step is to play the "What-if" game. For example, suppose we make the decision we want to increase player retention:<br />
<br />
<ul>
<li>What if we had more characters?</li>
<li>What if we had more levels?</li>
<li>What if the game were harder? easier?</li>
<li>What if we gave a bonus for playing every day?</li>
<li>What if we had daily challenges?</li>
<li>What if we highlight the leaderboard?</li>
</ul>
<br />
<h3>
Soft Launch</h3>
Exciting times for ScooterBoy! And lots of geek-out points writing queries in SQL to try and turn a mountain of data into usable information.<br />
<br />
We can't wait to make ScooterBoy even bigger and release in more markets!<br />
<br />
<div style="text-align: center;">
...watch this space...</div>
<div style="text-align: center;">
<br /></div>
<br />missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-15421429574212656462013-03-06T14:33:00.002-08:002013-03-06T14:34:23.699-08:00Mr LemonWow, we've been pretty busy with a whole bunch of things lately!<br />
<br />
It's not quite ready for the big reveal yet, so in the interim, here's an unmodified screenshot from a real tablet to show some of the cool new stuff:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrxf4CZL3KDOSmJ06lyyd9YIQ3sTvzYQmJsIqlm7DpZaZKFsEPtlEC6IzKvnRF6RWtIrzowLlYCKCqzrzbgQIuBb9pHAq_D3typ_G3lx2eBHMe6ZKQ_NesOV3PTewNXhA9I-GjxKt1f84/s1600/MrLemon.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrxf4CZL3KDOSmJ06lyyd9YIQ3sTvzYQmJsIqlm7DpZaZKFsEPtlEC6IzKvnRF6RWtIrzowLlYCKCqzrzbgQIuBb9pHAq_D3typ_G3lx2eBHMe6ZKQ_NesOV3PTewNXhA9I-GjxKt1f84/s640/MrLemon.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Click through for original size</td></tr>
</tbody></table>
You can see one of the new characters, Mr Lemon, pulling a wheelie, and wearing the always popular cowboy hat!<br />
<br />
As this is the first (tutorial) level, there's also a swipe hint to the player.<br />
<br />
And lastly, a debugging helper in the bottom left, 59 fps on the slowest iPad!!missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com1tag:blogger.com,1999:blog-6140632138569689510.post-31968067230878671512013-02-22T14:15:00.002-08:002013-02-22T14:15:51.479-08:00The SqueezeI've been adding a lot of content to ScooterBoy over the past week, and it's been causing some <i>problems</i>.<br />
<br />
In particular, the size of the archive had grown to over 100MB.<br />
<br />
Increasingly, I've come to realize that <i>speed of iteration</i> is one of the biggest factors in determining overall project success.<br />
<br />
The large archive size was causing slow sync times with the tablet, and even longer upload times on my rural broadband connection.<br />
<br />
Something had to be done.<br />
<br />
<h3>
Enter WebP</h3>
<br />
WebP is a relatively new graphics format (2010), published by Google, both patent-free and open-source.<br />
<br />
It's like a super-JPEG and a super-PNG all rolled in to one. Oh, and it fully supports alpha!<br />
<br />
Here's one I prepared earlier: <span style="font-size: xx-small;">(click through for full size images)</span><br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNKcFo2Ykroqbl_GFIdA5oPF-Td5u5avfhb40WHWgmte2Gr_itG1SyHOsMoEmp2Ul3ateXwnvxNfCrl8CzPimaXMlTdaE5G1fzsJ0Kkr-Subnt7xqdAtsHtgJJm1n-g0huZBtDZpfgZp0/s1600/SCTitle.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNKcFo2Ykroqbl_GFIdA5oPF-Td5u5avfhb40WHWgmte2Gr_itG1SyHOsMoEmp2Ul3ateXwnvxNfCrl8CzPimaXMlTdaE5G1fzsJ0Kkr-Subnt7xqdAtsHtgJJm1n-g0huZBtDZpfgZp0/s400/SCTitle.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Original PNG, 540KB</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqB1815A9jpf8dk-MUKr4W2gcInjhl5WQzB19NppeuI0eQKmmK1kWyaKppE2TazPDKR2T2uW5v_AsbzFNKGUh_Ogy4Zu0dS0dPQIanc1nTguDM6TosR9FkAodO8hUmAg3FnMW4ray5rEo/s1600/SCTitle.webp" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqB1815A9jpf8dk-MUKr4W2gcInjhl5WQzB19NppeuI0eQKmmK1kWyaKppE2TazPDKR2T2uW5v_AsbzFNKGUh_Ogy4Zu0dS0dPQIanc1nTguDM6TosR9FkAodO8hUmAg3FnMW4ray5rEo/s400/SCTitle.webp" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">WebP version, 23KB</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjufjaFbqGEmv-NLcShILH4OIbCvX18Ez7oQmLW3qYl00ylpU8fdAT8MbrRN-PWyAO0G9AD7OmsgvaELret-XhPgLe_bLnSpJ14xW1btTyj3siCtKeznrWZl-YfSosJJJcKmDZQkXB8_w4/s1600/SCTitle2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjufjaFbqGEmv-NLcShILH4OIbCvX18Ez7oQmLW3qYl00ylpU8fdAT8MbrRN-PWyAO0G9AD7OmsgvaELret-XhPgLe_bLnSpJ14xW1btTyj3siCtKeznrWZl-YfSosJJJcKmDZQkXB8_w4/s400/SCTitle2.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">(WebP version as lossless PNG, for comparison only)</td></tr>
</tbody></table>
In this particular example, that's a whopping 95.7% saving in space!!<br />
<br />
Obviously results will vary, but I'm consistently seeing 75% - 90% save spacing over the equivalent PNG/JPG, for a reasonable reduction in quality for tablet devices.<br />
<br />
I'm also finding that the compression artifacts are of a type that is less annoying than PNG or JPEG. (Apart from some YUV color noise at very low bitrates - hopefully google will fix this in an update)<br />
<br />
And it was super easy to integrate into my codebase.<br />
<br />
Want even more info? Go grab the source over at <a href="https://developers.google.com/speed/webp/" target="_blank">developers.google.com</a><br />
<br />
<br />
And my archive size? Now down to a very manageable 22MB.<br />
<br />
<br />missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0tag:blogger.com,1999:blog-6140632138569689510.post-7663487262691915592013-01-30T15:03:00.001-08:002013-01-30T15:03:43.585-08:00Pinata!Any game of appreciable size needs a mini-game, and this one is ours!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS9hR3G3UqnHw-GKwrIgTjTCb3j_KoPh95xBoS7rkwYZSf4zRUCrsWv_pIHWOYgUsIq_qx6CI_ecvtVESXAoV-eGvj1Ajj0FyhQrnfN4FvljySTrDxiyP9qwJ4Jbek_0PLnwpl8vTHgnk/s1600/minigame.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS9hR3G3UqnHw-GKwrIgTjTCb3j_KoPh95xBoS7rkwYZSf4zRUCrsWv_pIHWOYgUsIq_qx6CI_ecvtVESXAoV-eGvj1Ajj0FyhQrnfN4FvljySTrDxiyP9qwJ4Jbek_0PLnwpl8vTHgnk/s400/minigame.jpg" width="400" /></a></div>
<br />
We're calling it the "Treasure Mushroom". Use the multi-touch to knock the piñata, then collect the treasures that are hidden inside!<br />
<br />
It's a great way to give the player a random reward without resorting to a gambling metaphor like a roulette wheel or slot machine.<br />
<br />
<h3>
What makes a good mini-game?</h3>
I'm a big believer in the so called "<a href="http://www.gamasutra.com/view/feature/167214/rational_design_the_core_of_.php?print=1" target="_blank">Rational Game Design</a>" approach. In particular, the variety matrix. It suggests you can break down your game into a number of axes, such as time-pressure, activity, space modifier, etc.<br />
<br />
It then provides a recipe for combining those axes into novel variations. This aids the game designer's evaluation process and helps find the combinations which work the best.<br />
<br />
Under this framework, the mini-game is part of "exotic gameplay". It changes the pace of the game by giving the player a new challenge, or a much needed break.<br />
<br />
The mini-game must also be very easy to learn, and never punish the player, only reward.<br />
<br />
Lastly, your mini-game must remain thematically similar to your main game. In "ScooterBoy", both the main-game and the mini-game have 'collecting' as a central theme.<br />
<br />
What's your favourite/least-favourite mini games? Why not let me know in the comments below?<br />
<br />
<br />missingbyteshttp://www.blogger.com/profile/00276195535678106593noreply@blogger.com0