Skip to content

Instantly share code, notes, and snippets.

@marzapower
Last active August 29, 2015 14:04
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marzapower/60950151e112d9ca7c6d to your computer and use it in GitHub Desktop.
Save marzapower/60950151e112d9ca7c6d to your computer and use it in GitHub Desktop.
Swift Ninja Final Challenge
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
@marzapower
Copy link
Author

This is a simple but quickly-extensible solution to the Final Challenge for the Swift Ninja Challenge.

I decided to create a structure for quickly designing rules to compute the value of a hand, so it will be sufficient to increase the rules array with more rules to make the whole computation more complex.

By default the two rules cannot overlap, but just in case they do (if you extend the rule set, obviously), the highest scoring one will be taken into consideration.

@marzapower
Copy link
Author

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 ...

@icanzilb
Copy link

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?

@dkra89
Copy link

dkra89 commented Jul 24, 2014

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.

@marzapower
Copy link
Author

@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