tag:swift.svbtle.com,2014:/feedGame Development in Swift2015-02-28T07:59:42-08:00T. Urttihttps://swift.svbtle.comittrut@gmail.comSvbtle.comtag:swift.svbtle.com,2014:Post/the-road-to-1000-downloads2015-02-28T07:59:42-08:002015-02-28T07:59:42-08:00The Road To 1000 Downloads<p>Today is a day of celebration, the cumulative downloads of my 3 iOS games broke the one thousand mark arriving at 1005 downloads! </p>
<p>It is exactly 153 days since the release of the first game. </p>
<p>I don’t know how representative this is of an average indie developer’s experience, but it’s certainly very different than the numbers of Rovio or Supercell. Of course, in all honesty, my games are also less refined. Generally speaking I’m happy, as every one of my releases has racked up downloads faster than the previous ones, and more importantly I have received positive feedback from the gamers.</p>
<p>Below I have added the downloads graph so far. All the games have followed a very similar pattern. The downloads shoot up at release, but crash down within a couple days. </p>
<p><img src="http://www.weebly.com/uploads/4/6/1/8/46180249/7383065_orig.png" alt="Alt text"></p>
<p>Game of Roads was reviewed by 148apps (<a href="http://www.148apps.com/reviews/game-roads-solo-review/">http://www.148apps.com/reviews/game-roads-solo-review/</a>) which lead to a nice increase in downloads for 2-3 days. Also, making the games free lead to a temporary increase in downloads, this is due to the fact that numerous price monitoring websites notice the drop and people (mostly U.S. gamers) find it this way.</p>
<p>One of the most interesting things for me regarding sales has been following how it’s being downloaded all around the world. Below you can find a map where the darker shades of blue mean more downloads.</p>
<p><img src="http://www.weebly.com/uploads/4/6/1/8/46180249/3153756_orig.png" alt="Alt text"></p>
<p>I’ve localized 7 of Clubs and Finnish Dog to English and Finnish. Game of Roads is at least currently in the version 2.0 only in English. I could imagine downloads might pick up in other countries with localized content, since all of my top countries except Finland are English-speaking countries at the moment.</p>
<p><img src="http://www.weebly.com/uploads/4/6/1/8/46180249/1775852_orig.png" alt="Alt text"></p>
<p>There’s not much here that hasn’t mentioned in other articles before, but it really fits right in with most articles I’ve read on the topic: </p>
<ol>
<li>Release dates are highly important.</li>
<li>Price drops give temporary increases in sales.</li>
<li>Free games get WAY more downloads than paid ones.</li>
<li>Reviews give temporary increases in sales. </li>
</ol>
tag:swift.svbtle.com,2014:Post/background-layer2015-01-29T11:45:13-08:002015-01-29T11:45:13-08:00Programmatic Background Gradient Layer<p>I saw an interesting post about gradient programmatically that was written in Objective-C: <a href="https://danielbeard.wordpress.com/2012/02/25/gradient-background-for-uiview-in-ios/">https://danielbeard.wordpress.com/2012/02/25/gradient-background-for-uiview-in-ios/</a></p>
<p>I ported to Swift for my own use and it seems to work fine still! </p>
<pre><code class="prettyprint">import Foundation
import QuartzCore
import SpriteKit
class BackgroundLayer
{
var greyGradient = CAGradientLayer()
var blueGradient = CAGradientLayer()
init()
{
var colorOne = UIColor(white: 0.9, alpha: 1.0)
var colorTwo = UIColor(hue: 0.625, saturation: 0.0, brightness: 0.85, alpha: 1.0)
var colorThree = UIColor(hue: 0.625, saturation: 0.0, brightness: 0.7, alpha: 1.0)
var colorFour = UIColor(hue: 0.625, saturation: 0.0, brightness: 0.4, alpha: 1.0)
var colors = [CGColor](arrayLiteral: colorOne.CGColor, colorTwo.CGColor, colorThree.CGColor, colorFour.CGColor)
println(colors.count)
var locations = [CGFloat](arrayLiteral: 0.0, 0.02, 0.99, 1.0)
greyGradient.colors = colors;
greyGradient.locations = locations;
var blueColors = [UIColor]()
blueColors.append(UIColor(red: 120/255.0, green: 135/255.0, blue: 150/255.0, alpha: 1.0))
blueColors.append(UIColor(red: 57/255.0, green: 79/255.0, blue: 96/255.0, alpha: 1.0))
var bColors = [CGColor]()
for color in blueColors
{
bColors.append(color.CGColor)
}
var bStoppers = [CGFloat](arrayLiteral: 1.0, 1.0)
blueGradient.colors = bColors
blueGradient.locations = bStoppers
}
}
</code></pre>
tag:swift.svbtle.com,2014:Post/localizing-sklabelnodes-from-sks-files2014-09-07T12:57:57-07:002014-09-07T12:57:57-07:00Localizing SKLabelNodes in .sks files<p>Most of my first scenes I implemented by code instead of the GUI tool, but eventually I thought it could be quite helpful for certain scenes. </p>
<p>I quickly noticed the issue that it was not so straightforward to localize the SKLabelNode texts anymore. </p>
<p>I tried the default method by clicking ‘Localize…’ button in the tool, but that actually made duplicates of the .sks file that I was supposed to change for localizing the texts. This seemed to have the bad side that if I were to make changes to the layout or add new elements, I would have to do it multiple times.</p>
<p>Instead I implemented this bit of code where I unarchive the .sks files. This is what the default unarchive function more or less looks like:</p>
<pre><code class="prettyprint">extension SKNode {
class func unarchiveFromFile(file : NSString) -> SKNode? {
let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks")
var sceneData = NSData.dataWithContentsOfFile(path!, options: .DataReadingMappedIfSafe, error: nil)
var archiver = NSKeyedUnarchiver(forReadingWithData: sceneData)
archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as SKScene
archiver.finishDecoding()
scene.scaleMode = .AspectFill
localizeLabelNodes(scene)
return scene
}
}
</code></pre>
<p>For this article the interesting bit is the call to localizeLabelNodes. There I do this:</p>
<pre><code class="prettyprint">func localizeLabelNodes(scene : SKScene)
{
for node in scene.children
{
if var labelNodeText = (node as? SKLabelNode)?.text
{
var index = advance(labelNodeText.startIndex, 4)
if labelNodeText.substringToIndex(index) == "L:::"
{
var langId = labelNodeText.substringFromIndex(index)
(node as? SKLabelNode)?.text = NSLocalizedString(langId, comment: langId)
}
}
}
}
</code></pre>
<p>So basically I enumerate the SKLabelNodes of the scene, and if the text matches the pattern “L:::”, I know that this is something to localize. Then I simply the substring as the translation ID. </p>
<p>Example:<br>
In .sks file, SKLabelNode.text : “L:::New Game”<br>
In localizable.strings (English): “New Game” = “New Game”;<br>
In localizable.strings (Finnish): “New Game” = “Uusi Peli”;</p>
<p>This way when I want to change translations of .sks SKLabelNodes, I can segregate changes to the strings file like elsewhere.</p>
tag:swift.svbtle.com,2014:Post/multiplayer-elo-score-in-swift2014-08-17T14:22:06-07:002014-08-17T14:22:06-07:00Multiplayer ELO score in Swift<p>I’m in the process of developing my first game for iOS. At first I wanted to include the so-called ELO score in the 2nd or 3rd version of the game, but this week my thoughts came around and now I believe that the competitiveness factor that leaderboards and a global ranking bring to the game should be a first release feature.</p>
<p>The Elo-score in short is a system that ranks players in comparison to their peers. Losing a game to a better player is not as bad as losing against a worse player. You also gain more by beating opponents that are better than you. Elo was created for duel games, so it remains to be seen how well it works here. </p>
<p>The design of the multiplayer Elo here is identical to the duel Elo, the only difference being that all players are compared to all their opponents. Please find below the code, hope it helps! I have only tested it shortly and it seems to be working fine for now.</p>
<pre><code class="prettyprint"> func adjustEloScores()
{
var qScores = Double[]()
// Populate the QScores, according to ELO-system
for player in allPlayers
{
qScores.append(pow(10.0, Double(player.ELO / 400)))
}
// Calculate and apply delta to each player ELO
for (indexP, player) in enumerate(allPlayers)
{
var eScores = Double[]()
var sScores = Double[]()
for (indexQ, qScore) in enumerate(qScores)
{
if indexP != indexQ
{
eScores.append(qScores[indexP] / (qScores[indexP] + qScore))
sScores.append(player.finishedInPosition < allPlayers[indexQ].finishedInPosition ? 1.0 : 0.0)
}
}
var deltaELO = 0
for (i, eS) in enumerate(eScores)
{
deltaELO += Int(KFACTOR * (sScores[i] - eS))
}
player.ELO += deltaELO
player.deltaELO = deltaELO
}
}
</code></pre>
tag:swift.svbtle.com,2014:Post/how-swift-is-swift-compared-to-c2014-06-15T16:11:24-07:002014-06-15T16:11:24-07:00How swift is Swift compared to C++?<p>Merriam-Webster defines swift as <em>“moving or capable of moving at great speed”</em>. Apple also presented similar promises at their WWDC 2014 keynote presentation, where Swift was first released. In one of the slides there was a comparison for RC4 encryption that Swift did 220x faster than Python and almost 2x faster than Objective-C.</p>
<p><img src="http://regmedia.co.uk/2014/06/02/swift_benchmark.jpg" alt="Alt text"></p>
<p>What about the classical behemoth of performance C++? Which one of these two languages takes the cake when it comes to calculating the Collatz conjecture for numbers under 1 million? Let’s find out! </p>
<p>I made an effort to keep the solutions as similar as possible to have a fair comparison. First I will show you the full source code of both solutions and finally the results. </p>
<h1 id="c-solution_1">C++ Solution <a class="head_anchor" href="#c-solution_1">#</a>
</h1>
<pre><code class="prettyprint">#include <iostream>
#include <sys/time.h>
int main(int argc, const char * argv[])
{
// Take starting time for performance measurement
struct timeval start, end;
gettimeofday(&start, NULL);
// Define the range for testing
const int FROM = 2;
const int UNTIL = 999999;
// Save sequence lengths in array for performance gains
const int ARRAY_SIZE = 1000000;
int sequenceArray[ARRAY_SIZE];
// Initialize all to -1
for (int i = 0; i < ARRAY_SIZE; ++i)
{
sequenceArray[i] = -1;
}
sequenceArray[1] = 0;
// Loop each number in the range
for (int number = FROM; number < UNTIL; ++number)
{
long value = number;
int sequence = 0;
// If previously calculated, no need to recalculate
bool notFound = sequenceArray[value] < 0;
while (notFound)
{
// Actual calculation of the Collatz conjecture
value = value % 2 == 0 ? value / 2 : value * 3 + 1;
++sequence;
// Need to set true for those outside range to avoid runtime error
notFound = (value < (ARRAY_SIZE - 1)) ? (sequenceArray[value] < 0) : true;
}
sequence += sequenceArray[value];
sequenceArray[number] = sequence;
}
// Now find out which one had the longest sequence
int valueWithLongestSequence = 0;
int longestSequence = 0;
for (int number = FROM; number < UNTIL; ++number)
{
if (sequenceArray[number] > longestSequence)
{
longestSequence = sequenceArray[number];
valueWithLongestSequence = number;
}
}
// Performance comparison code
gettimeofday(&end, NULL);
printf ("time = %d ms\n", (end.tv_usec - start.tv_usec) / 1000);
// Output result
std::cout << "DONE! Value " << valueWithLongestSequence << " has longest sequence " << longestSequence << ".\n";
return 0;
}
</code></pre>
<h1 id="swift-solution_1">Swift Solution <a class="head_anchor" href="#swift-solution_1">#</a>
</h1>
<p>See more information about the Swift solution here: <br>
<a href="http://swift.svbtle.com/calculating-the-collatz-conjecture-with-swift">http://swift.svbtle.com/calculating-the-collatz-conjecture-with-swift</a></p>
<pre><code class="prettyprint">// Import Foundation for taking execution time with NSDate
import Foundation
// Take starting time for performance measurement
var start = NSDate()
// Define the range for testing
let FROM = 2
let UNTIL = 999_999
// Save sequence lengths in array for performance gains
let ARRAY_SIZE = 1_000_000
let stepsArray = Array(count: ARRAY_SIZE, repeatedValue: -1)
stepsArray[1] = 0
// Loop each number in the range
for number in FROM...UNTIL
{
var value = number
var steps = 0
// If previously calculated, no need to recalculate
var notFound = stepsArray[value] < 0
while (notFound)
{
// Actual calculation of the Collatz conjecture
value = value % 2 == 0 ? value / 2 : value * 3 + 1
++steps
// Need to set true for those outside range to avoid runtime error
notFound = value < (ARRAY_SIZE - 1) ? stepsArray[value] < 0 : true
}
steps += stepsArray[value]
stepsArray[number] = steps
}
// Now find out which one had the longest sequence
var longestSequence : (Int, Int) = (0, 0)
for number in FROM...UNTIL
{
if stepsArray[number] > longestSequence.1
{
// Set longest sequence tuple to hold the number and sequence length
longestSequence = (number, stepsArray[number])
}
}
// Performance comparison code
var end = NSDate()
var timeTaken = end.timeIntervalSinceDate(start) * 1000
println("Time taken: \(timeTaken) ms.")
// Output result
println("DONE! Value \(longestSequence.0) has longest sequence \(longestSequence.1)")
</code></pre>
<h1 id="performance-evaluation_1">Performance evaluation <a class="head_anchor" href="#performance-evaluation_1">#</a>
</h1>
<p>As you notice the solution used is identical, the code even looks very similar. The performance was measured using an Early 2011 Macbook Pro with a 2,2 Ghz i7 processor. The operating system used was the beta OS X 10.10 Yosemite and both solutions were compiled with the XCode 6.0 beta. Compiler for C++ was Apple LLVM 6.0.</p>
<p>I first ran both applications directly from the XCode development view four times to gain confidence in the results. </p>
<table>
<thead>
<tr>
<th></th>
<th>Swift</th>
<th>C++</th>
</tr>
</thead>
<tbody>
<tr>
<td>Run 1</td>
<td>15165 ms</td>
<td>157 ms</td>
</tr>
<tr>
<td>Run 2</td>
<td>14942 ms</td>
<td>156 ms</td>
</tr>
<tr>
<td>Run 3</td>
<td>14863 ms</td>
<td>164 ms</td>
</tr>
<tr>
<td>Run 4</td>
<td>14679 ms</td>
<td>151 ms</td>
</tr>
</tbody>
</table>
<p>The performance difference was in fact quite stunning. On average C++ was approximately 100x faster. Swift ran for approximately 15 seconds, while C++ only took approximately 150 milliseconds. </p>
<p>It’s of course good to remember here that C++ has been actively developed for around 31 years and as such has evolved into quite a performance beast, whereas Swift was only released 2 weeks ago. </p>
<p>But then I found some comments here indicating that the performance gap can be bridged by changing the compiler options of Swift: <a href="https://stackoverflow.com/questions/24101718/swift-performance-sorting-arrays">https://stackoverflow.com/questions/24101718/swift-performance-sorting-arrays</a></p>
<p>Let’s investigate!</p>
<p>I next compiled and ran the Swift application with the available compiler options. For C++ it seemed like there was no substantial difference between the different optimizations (O, O2, O3, Ofast) as long as they were enabled. </p>
<table>
<thead>
<tr>
<th>Language</th>
<th>Swift</th>
<th>Swift</th>
<th>Swift</th>
<th>C++</th>
<th>C++</th>
</tr>
</thead>
<tbody>
<tr>
<td>Compiler Option</td>
<td>None</td>
<td>Fastest</td>
<td>Fastest, Unchecked</td>
<td>None</td>
<td>Fastest</td>
</tr>
<tr>
<td>Run 1</td>
<td>16680 ms</td>
<td>983 ms</td>
<td>38 ms</td>
<td>164 ms</td>
<td>35 ms</td>
</tr>
<tr>
<td>Run 2</td>
<td>17057 ms</td>
<td>1030 ms</td>
<td>54 ms</td>
<td>180 ms</td>
<td>27 ms</td>
</tr>
<tr>
<td>Run 3</td>
<td>16971 ms</td>
<td>1004 ms</td>
<td>35 ms</td>
<td>172 ms</td>
<td>18 ms</td>
</tr>
<tr>
<td>Run 4</td>
<td>17035 ms</td>
<td>1036 ms</td>
<td>41 ms</td>
<td>206 ms</td>
<td>19 ms</td>
</tr>
</tbody>
</table>
<p>Performance crown seems to stand firmly in the C++ corner as things are today. With no compiler optimization C++ beats Swift with a whopping 100x factor. When compiler optimizations are enabled C++ still takes only half the time of Swift in this particular test. </p>
<p>All this said, there are more things than performance to a language and so far Swift has certainly been a pleasure to learn and there many small things it does do smarter than C++.</p>
<p><strong>EDIT: It was pointed out to me that C++ was using 32-bit integers, while Swift was using 64-bit. After changing the C++ implementation to match with regard to this I re-ran and found that the times increased to the range of 31-46ms with -O3 and 29-33ms with -Ofast. It seems that the margin is certainly small in this test and it’s possible that the small differences in code account for the rest of the difference. Fundamentally for this test, the solutions seem more or less equally fast.</strong></p>
tag:swift.svbtle.com,2014:Post/calculating-the-collatz-conjecture-with-swift2014-06-15T14:09:10-07:002014-06-15T14:09:10-07:00Calculating the Collatz conjecture with Swift<p>The Collatz conjecture is a mathematical conjecture named after Lothar Collatz. The basic idea is described in Wikipedia as the following:</p>
<p><em>“Take any natural number n. If n is even, divide it by 2 to get n / 2. If n is odd, multiply it by 3 and add 1 to obtain 3n + 1. Repeat the process (which has been called "Half Or Triple Plus One”, or HOTPO[6]) indefinitely. The conjecture is that no matter what number you start with, you will always eventually reach 1.“</em></p>
<p>So fundamentally very simple mathematics. So let’s get started by defining the range of natural numbers to test and creating an array where to store results to increase efficiency dramatically.</p>
<pre><code class="prettyprint lang-Swift">// Range we test
let FROM = 2
let UNTIL = 999_999
// Save sequence lengths in array for gains in performance
let ARRAY_SIZE = 1_000_000
let stepsArray = Array(count: ARRAY_SIZE, repeatedValue: -1)
stepsArray[1] = 0
</code></pre>
<p>Notice the nice underscore syntax Swift allows for improving the readability of large numbers: 1_000_000 instead of 1000000. </p>
<p>You might wonder why the stepsArray is defined as a constant instead of a variable. The ‘let’ definition here does not mean that contents of the array cannot be modified. It means that the array cannot be resized during runtime, as variable Swift arrays seem to be closer to C++ vectors than C-style arrays.</p>
<p>Apple recommends creating constant arrays for efficiency when resizing is not required:<br>
<em>”It is good practice to create immutable collections in all cases where the collection’s size does not need to change. Doing so enables the Swift compiler to optimize the performance of the collections you create.”</em></p>
<ul>
<li>Apple Inc. ”The Swift Programming Language”. iBooks. <a href="https://itun.es/fi/jEUH0.l">https://itun.es/fi/jEUH0.l</a><br>
</li>
</ul>
<p>Next we iterate over the range.</p>
<pre><code class="prettyprint lang-Swift">// Loop each number in the range
for number in FROM...UNTIL
{
var value = number
var steps = 0
// If previously calculated, no need to recalculate
var notFound = stepsArray[value] < 0
while (notFound)
{
// Actual calculation of the Collatz conjecture
// If even, divide by 2. If odd, multiply by 3 and add one.
value = value % 2 == 0 ? value / 2 : value * 3 + 1
++steps
// Limit range to avoid overflow runtime error
notFound = value < (ARRAY_SIZE - 1) ? stepsArray[value] < 0 : true
}
steps += stepsArray[value]
stepsArray[number] = steps
}
</code></pre>
<p>The above should quite self-explanatory. Now that everything is calculated we just need to check which number had the longest path to reach 1 in our range and place it in the longestSequence tuple (starting number and step count to reach 1).</p>
<pre><code class="prettyprint lang-Swift">// Now find out which one had the longest sequence
var longestSequence : (Int, Int) = (0, 0)
for number in FROM...UNTIL
{
if stepsArray[number] > longestSequence.1
{
// Set longest sequence tuple to hold the number and sequence length
longestSequence = (number, stepsArray[number])
}
}
println("DONE! Value \(longestSequence.0) has longest sequence \(longestSequence.1)")
</code></pre>
<p>And done! Follow-up to this article will be a performance comparison of this solution against a C++ solution. </p>
tag:swift.svbtle.com,2014:Post/dealing-with-large-numbers-in-swift2014-06-13T14:45:48-07:002014-06-13T14:45:48-07:00Dealing with large numbers in Swift<p>Type inference is a handy feature in Swift that makes declaring most variables fun and easy. However, there are cases when you must explicitly define the type of the variable. </p>
<p>In this example, the starting point is having 4 big numbers, each consisting of 50 digits. Normally you might try to put them into a variable with type inference, like this:</p>
<pre><code class="prettyprint lang-Swift">var numbers =
[37107287533902102798797998220837590246510135740250,
46376937677490009712648124896970078050417018260538,
74324986199524741059474233309513058123726617309629,
91942213363574161572522430563301811072406154908250]
</code></pre>
<p>Since the compiler is getting an integer like number fed to it, it tries to automatically use the type Int (Int64 on a 64-bit platform, Int32 on a 32-bit platform). This leads to a compile-time error of an overflow. Since the numbers are too big even for an UInt64 type, we must use floating point here. With floating point there is less precision, but let’s not worry too much about that right now.</p>
<pre><code class="prettyprint lang-Swift">var numbers : Double[] =
[37107287533902102798797998220837590246510135740250,
46376937677490009712648124896970078050417018260538,
74324986199524741059474233309513058123726617309629,
91942213363574161572522430563301811072406154908250]
</code></pre>
<p>Now the code compiles!</p>
<p>If you want to calculate the sum of these, you can simply do the following:</p>
<pre><code class="prettyprint lang-Swift">var sum : Double = 0
for number in numbers
{
sum += number
}
sum
</code></pre>
<p>As you see here I must again explicitly define the “sum” variable to be of type Double due to the size of the numbers being calculated. However, I can use type inference in the for-in loop for the constant called “number” since the numbers array is already of type Double[]. </p>
tag:swift.svbtle.com,2014:Post/looping-through-an-array-of-arrays-with-swift-12014-06-11T15:09:52-07:002014-06-11T15:09:52-07:00Looping through an array of arrays with Swift<p>…and finding the greatest product horizontally, vertically or diagonally.</p>
<hr>
<p>Finding out the largest product was fairly simple using Swift. The global enumerate function for looping through the arrays was an especially nice feature. It returns a tuple with the value and the index, see more in Apple’s Book “The Swift Programming Language” page 102. You can read the book from Apple’s iBooks for free.</p>
<hr>
<p>Since this is my first Swift post I will post event the copyright header to show you what Xcode generates.</p>
<pre><code class="prettyprint lang-swift">//
// main.swift
//
// Created by T. Urtti on 11.6.2014.
// Copyright (c) 2014 T. Urtti. All rights reserved.
//
</code></pre>
<p>After this I create the array of int arrays. Now notice how I don’t declare anything explicitly to be an array nor do I explicitly define anything to be integer. This code fully utilizes the type inference that is a part of Swift. The compiler understands automatically that the gridOfGrids is an array and that the array elements are int arrays. </p>
<pre><code class="prettyprint lang-swift">let gridOfGrids = [
[08, 02, 22, 97, 38, 15, 00, 40, 00, 75, 04, 05, 07, 78, 52, 12, 50, 77, 91, 08],
[49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48, 04, 56, 62, 00],
[81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30, 03, 49, 13, 36, 65],
[52, 70, 95, 23, 04, 60, 11, 42, 69, 24, 68, 56, 01, 32, 56, 71, 37, 02, 36, 91],
[22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80],
[24, 47, 32, 60, 99, 03, 45, 02, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50],
[32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70],
[67, 26, 20, 68, 02, 62, 12, 20, 95, 63, 94, 39, 63, 08, 40, 91, 66, 49, 94, 21],
[24, 55, 58, 05, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72],
[21, 36, 23, 09, 75, 00, 76, 44, 20, 45, 35, 14, 00, 61, 33, 97, 34, 31, 33, 95],
[78, 17, 53, 28, 22, 75, 31, 67, 15, 94, 03, 80, 04, 62, 16, 14, 09, 53, 56, 92],
[16, 39, 05, 42, 96, 35, 31, 47, 55, 58, 88, 24, 00, 17, 54, 24, 36, 29, 85, 57],
[86, 56, 00, 48, 35, 71, 89, 07, 05, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58],
[19, 80, 81, 68, 05, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77, 04, 89, 55, 40],
[04, 52, 08, 83, 97, 35, 99, 16, 07, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66],
[88, 36, 68, 87, 57, 62, 20, 72, 03, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69],
[04, 42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18, 08, 46, 29, 32, 40, 62, 76, 36],
[20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74, 04, 36, 16],
[20, 73, 35, 29, 78, 31, 90, 01, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57, 05, 54],
[01, 70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52, 01, 89, 19, 67, 48]]
</code></pre>
<p>You may have noticed I declared it using the keyword ‘let’ instead of ‘var’. This is to make the array constant, un-modifiable.</p>
<p>Now I will calculate the max index for a diagonal product calculation and also declare that a constant. And define the variable that gets updated with the largest product.</p>
<pre><code class="prettyprint lang-swift">let maxIndex = gridOfGrids[0].count - 4
var largestProduct = 0
</code></pre>
<p>Now this is more exciting. Swift gives you a very handy enumerate function for looping through an array. The enumerate function returns a tuple including both index and the actual value. Yes, you can use tuples in Swift.</p>
<p>I won’t talk more in detail about the actual product checks in the loops as they are quite generic to any programming language. </p>
<pre><code class="prettyprint lang-swift">for (rowIndex, row) in enumerate(gridOfGrids)
{
for (columnIndex, number) in enumerate(row)
{
// Horizontal check
if (columnIndex >= 3)
{
var product = row[columnIndex-3] *
row[columnIndex-2] *
row[columnIndex-1] *
number
if largestProduct < product
{
largestProduct = product
}
}
// Vertical check
if (rowIndex >= 3)
{
var product = (gridOfGrids[rowIndex-3])[columnIndex] *
(gridOfGrids[rowIndex-2])[columnIndex] *
(gridOfGrids[rowIndex-1])[columnIndex] *
number
if largestProduct < product
{
largestProduct = product
}
}
// Diagonal up-left -> bottom-right
if (rowIndex >= 3 && columnIndex >= 3)
{
var product = (gridOfGrids[rowIndex-3])[columnIndex-3] *
(gridOfGrids[rowIndex-2])[columnIndex-2] *
(gridOfGrids[rowIndex-1])[columnIndex-1] *
number
if largestProduct < product
{
largestProduct = product
}
}
// Diagonal bottom-left -> up-right
if (rowIndex >= 3 && columnIndex <= maxIndex)
{
var product = (gridOfGrids[rowIndex-1])[columnIndex+1] *
(gridOfGrids[rowIndex-2])[columnIndex+2] *
(gridOfGrids[rowIndex-3])[columnIndex+3] *
number
if largestProduct < product
{
largestProduct = product
}
}
}
}
</code></pre>
<p>And finally just a simple printout to find out what was actually calculated in all of this. Println apparently is somehow a context-aware function that prints to the appropriate output. In Xcode it printed to the debug output.</p>
<pre><code class="prettyprint lang-swift">println("Largest Product: " + String(largestProduct))
</code></pre>
<p>Great, that wasn’t too difficult! Overall the syntax feels more or less at home for somebody coming mainly from a C++ background. </p>