Last active
August 29, 2015 14:04
-
-
Save marzapower/60950151e112d9ca7c6d to your computer and use it in GitHub Desktop.
Swift Ninja Final Challenge
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
/* | |
* Expresses a generic rule for computing card values | |
*/ | |
struct Rule { | |
// Should return true if the rule is appliable | |
let applies : (currentCard:Card, previousCard:Card?) -> Bool | |
// Returns the computed value for the current card | |
let exec : (card:Card) -> Int | |
} | |
/* | |
* Keeps track of the total score of the hand and the last card | |
* that has been evaluated | |
*/ | |
struct Sum { | |
var total : Int | |
var lastCard : Card? | |
} | |
/* | |
* Extracts the integer value of the card's rank | |
*/ | |
func cardValue(card : Card?) -> Int { | |
if card?.rank { | |
switch(card!.rank) { | |
case .Ace : return 1 | |
case .King : return 13 | |
case .Queen : return 12 | |
case .Jack : return 11 | |
case .Num(let value) : return value | |
} | |
} else { | |
return 0 | |
} | |
} | |
/* | |
* This rule expresses rule n. 1 for computing card values | |
*/ | |
let aces = Rule( | |
applies: { currentCard, previousCard in | |
return cardValue(currentCard) == 1 && cardValue(previousCard?) == 5 && previousCard?.suit == Suit.Diamonds | |
}, exec: { card in return 100 }) | |
/* | |
* This rule expresses rule n. 2 for computing card values | |
*/ | |
let oddity = Rule( | |
applies: { currentCard, previousCard in | |
return cardValue(currentCard)%2==1 && previousCard?.suit == Suit.Hearts | |
}, exec: { card in return cardValue(card)*2 }) | |
let rules = [aces, oddity] // More rules could be added ... if necessary | |
/* | |
* Applies a set of rules to the current card using the previous one as the reference | |
*/ | |
func applyRules(rules: [Rule], currentCard: Card, previousCard: Card?) -> Int { | |
return maxElement(rules.map{ rule in rule.applies(currentCard: currentCard, previousCard: previousCard) ? rule.exec(card: currentCard) : 0 }) | |
} | |
/* | |
* Counts the hand applying a global set of rules to its sequence of cards | |
*/ | |
func countHand(cards : [Card]) -> Int { | |
return cards.reduce(Sum(total: 0, lastCard: nil)) { sum, currentCard in | |
Sum(total: sum.total + applyRules(rules, currentCard, sum.lastCard), lastCard: currentCard) | |
}.total | |
} | |
let result = countHand([ | |
Card(suit:Suit.Hearts, rank:Rank.Ace), | |
Card(suit:Suit.Hearts, rank:Rank.Num(10)), | |
Card(suit:Suit.Hearts, rank:Rank.Num(6)), | |
Card(suit:Suit.Diamonds, rank:Rank.Num(5)), | |
Card(suit:Suit.Clubs, rank:Rank.Ace), | |
Card(suit:Suit.Diamonds, rank:Rank.Jack) | |
]) //--> 110 |
Nice job! I like that the solution is extensible :)
Is there an option to enable the color coding so the readers can read the code easier?
I like your solution very much but there are two little errors. In both of your rules you just assume that previousCard is not nil and force-unwrapped it using the '!' - Operator. It only works with the given example because the first Card is no Ace and an even Card.
@icanzlib: I've already set up the Gist to use the Swift language. Any missing code coloring is due to Github :)
@dkra89: thank you for the suggestion. I was using a slightly different version locally and I didn't notice the error. The updated version should be fine!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
P.S. I've updated the code to make it a little more readable. I could save some space compressing the functions, but making the whole code cryptic is not my target here ...