Swift Ninja Programming Challenge: Winners Announced!
Check out the winners of our recent Swift NInja programming challenge! By Marin Todorov.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Swift Ninja Programming Challenge: Winners Announced!
10 mins
We recently had a 2-part “Swift Ninja” programming challenge:
- The first part of this series contains programming challenges involving default values in functions, variadic parameters, map/reduce, advanced switch statement features, and more.
- The second part of the series contains programming challenges involving recursion, operator overloading, lazy evaluation, currying, and more.
Be sure to try the challenges if you haven’t already. They’re a great way to practice your new Swift skills, and you’ll learn a ton!
At the end of the second part, we had a special final challenge that was open to competition among readers for fame and fortune.
Well, we’ve had a ton of great entries, and today we’re going to announce the winner!
The Final Challenge
Let’s start by reviewing the final challenge:
Given the structures:
Write a function called countHand
that takes in an array of Card
instances and counts the total value of the cards given. The requirements for your solution are as follows:
- The function returns the value of the cards in the hand as an Int.
- Does not use loops or nested functions.
- Any Ace preceded by 5 of Diamonds is worth 100 points.
- Any odd numeric card (3, 5, 7, 9) of any suit’s worth the double of its rank value in points when immediately preceded in the hand by any card of the Hearts.
Given the structures:
enum Suit {
case Clubs, Diamonds, Hearts, Spades
}
enum Rank {
case Jack, Queen, King, Ace
case Num(Int)
}
struct Card {
let suit: Suit
let rank: Rank
}
Write a function called countHand
that takes in an array of Card
instances and counts the total value of the cards given. The requirements for your solution are as follows:
- The function returns the value of the cards in the hand as an Int.
- Does not use loops or nested functions.
- Any Ace preceded by 5 of Diamonds is worth 100 points.
- Any odd numeric card (3, 5, 7, 9) of any suit’s worth the double of its rank value in points when immediately preceded in the hand by any card of the Hearts.
enum Suit {
case Clubs, Diamonds, Hearts, Spades
}
enum Rank {
case Jack, Queen, King, Ace
case Num(Int)
}
struct Card {
let suit: Suit
let rank: Rank
}
The Participants
A number of brave ninjas submitted their solutions to the final challenge. Feast your eyes upon their code and praise their skills:
- marzapower: https://gist.github.com/marzapower/60950151e112d9ca7c6d
- zephyz: https://gist.github.com/zhaar/a718253eb4246ce729a8
- terkans: https://gist.github.com/maartenh/3c0b67dd423b2d0b62a0#file-counthand-swift
- pasil: https://gist.github.com/plecode/b8d85ca6b61ce994f2ca
- dojomaroc: https://gist.github.com/dodomaroc86/9bd753f5c3b3a46ba78a
- epinaud: https://gist.github.com/epinaud/7921885ae26ae2914f7b
- tomek: https://gist.github.com/tomekc/e25a23e6e42abcac4837
I recommend you check out all solutions – they are way more diverse than I initially expected. Nice job everyone and thank you very much for participating!
I considered a number of aspects while choosing the winner so let me share some of my observations while I was evaluating the code.
Correctness
All provided solutions produced correct results – congratulations everyone! I know the solution requirements were a bit strange, but it was only because I wanted to challenge you into creatively solve how to keep track of the last card’s value.
Some of the participants figured out that the first card in the hand never brings any value to the result. Even though their solutions aren’t producing a “more correct” result, it’s a nice optimization catch – kudos to Dojomaroc, Epinaud, and Tomek.
Brevity
Most of the participants embraced the code style of the article and produced tight and clean solutions. I personally like the solutions by Dojomaroc and Pasil – both of them kept the function code to a single return
statement where a single switch
plays the main role. Nice job!
Marzapower provided the longest but most flexible solution (check it out, well laid down busines logic there). He bravely went against my “brevity” requirement and receives an honorable mention for that!
Use of Swift features
Even though use of advanced Swift doesn’t always result in the fastest or shortest solution, it’s always interesting to see what other programmers create with this amazing language.
Terkans used the most exotic structure from the Swift standard library (that I must admit haven’t heard before I saw his code): Zip2
.
Zip2
‘s init takes in two SequenceType
values and combines them into a single Sequence made of the values bound into tuples. Cool! Check his solution for an example how to use Zip2
. Terkans also used the +
as the closure param to Array.reduce()
, which I liked very much.
Readability
Dojomaroc‘s solution was clearly the most readable just because he included a ton of comments. This is the kind of code I personally would love to see if I jump in on a project mid-way. Thumbs up!
Performance
Dojomaroc gave me an interesting idea with his comment, namely to measure the performance of each solution. Interestingly no the same solution performs best when I tested the solutions on a debug build and on a release build. I tested all solutions with the same card hand and letting each solution roll 100,000 times.
Dojomaroc and Tomek didn’t use optionals so their solutions came out first in the debug build measures (Dojomaroc’s solution sometimes coming few milliseonds faster). However the races between release builds came out quite different (lower result is better):
The fastest solution in the test clearly is Pasil‘s – thumbs up!
The Runner Up
It was extremely hard choosing between these solutions; I was very impressed with what everyone came up with.
In the end, it came down to two – and since it was so hard to decide, I wanted to give the runner up a prize as well.
The runner up is Pasil – congratulations! Ray will be in touch soon to deliver your prize – a free PDF of your choice from this site.
Here’s Pasil’s solution:
func countHand(cards: [Card]) -> Int {
return cards.reduce((nil, 0)) { (prev: (card: Card?, sum: Int), card: Card) in
if let prevCard = prev.card {
switch (prevCard.suit, prevCard.rank, card.rank) {
case (.Diamonds, .Num(5), .Ace):
return (card, prev.sum + 100)
case (.Hearts, _, .Num(let value)) where value % 2 == 1:
return (card, prev.sum + 2 * value)
default:
return (card, prev.sum)
}
}
return (card, 0)
}.sum
}