Last active
June 15, 2017 23:49
-
-
Save davidolesch/26338baf8cf0f85688ee02217d0ad8b8 to your computer and use it in GitHub Desktop.
This file contains 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
import Foundation | |
protocol Randomizable { | |
init?(rawValue:Int) | |
static var min:Int { get } | |
static var max:Int { get } | |
} | |
extension Randomizable { | |
static var random:Self? { | |
let index = min + Int(arc4random_uniform(UInt32(max))) | |
return Self(rawValue:index) | |
} | |
} | |
struct BlackjackCard { | |
enum Suit: Int, Randomizable, CustomStringConvertible { | |
var description: String { | |
switch self { | |
case .spades: | |
return "♠" | |
case .hearts: | |
return "♡" | |
case .diamonds: | |
return "♢" | |
case .clubs: | |
return "♣" | |
} | |
} | |
case spades, hearts, diamonds, clubs | |
static let min = Suit.spades.rawValue | |
static let max = Suit.clubs.rawValue | |
} | |
enum Rank: Int, Randomizable { | |
case two = 2, three, four, five, six, seven, eight, nine, ten | |
case jack, queen, king, ace | |
struct Values { | |
let first: Int, second: Int? | |
} | |
var values: Values { | |
switch self { | |
case .ace: | |
return Values(first: 1, second: 11) | |
case .jack, .queen, .king: | |
return Values(first: 10, second: nil) | |
default: | |
return Values(first: self.rawValue, second: nil) | |
} | |
} | |
static let min = Rank.two.rawValue | |
static let max = Rank.ace.rawValue | |
} | |
let rank: Rank, suit: Suit | |
var description: String { | |
var output = "[\(rank.values.first)" | |
if let second = rank.values .second { | |
output += " or \(second)" | |
} | |
output += " of \(suit.description)]" | |
return output | |
} | |
static func randomCard() -> BlackjackCard { | |
return BlackjackCard(rank: Rank.random ?? .two, suit: Suit.random ?? .spades) | |
} | |
} | |
class Hand { | |
var cards:[BlackjackCard] = [] | |
var value:Int { | |
var v = 0 | |
for card in cards { | |
v += card.rank.values.first | |
} | |
if soft && containsAce { | |
v += 10; | |
} | |
return v | |
} | |
var containsAce: Bool { | |
get { | |
return self.cards.contains { return $0.rank == .ace } | |
} | |
} | |
var soft:Bool { | |
var v = 0 | |
for card in cards { | |
v += card.rank.values.first | |
} | |
return v < 12 | |
} | |
var busted:Bool { | |
return value > 21 | |
} | |
var description:String { | |
var d = "" | |
for card in cards { | |
d += card.description + " " | |
} | |
return d | |
} | |
} | |
class Participant { | |
var hand = Hand() | |
} | |
class Dealer: Participant { | |
var upCard:BlackjackCard? { | |
return self.hand.cards.last | |
} | |
func dealInitialHandsToParticipants(participants: [Participant]) { | |
for participant in participants { | |
dealACardToParticipant(participant: participant) | |
dealACardToParticipant(participant: participant) | |
} | |
} | |
func dealACardToParticipant(participant: Participant) -> BlackjackCard { | |
let card = BlackjackCard.randomCard() | |
participant.hand.cards.append(card) | |
return card | |
} | |
func dealToFinish() -> Hand { | |
while hand.value < 17 { | |
dealACardToParticipant(participant: self) | |
} | |
return hand | |
} | |
func beat(player:Player) -> Bool { | |
if player.hand.busted { | |
return true | |
} | |
if self.hand.busted { | |
return false | |
} | |
return player.hand.value <= self.hand.value | |
} | |
} | |
class Player: Participant { | |
func playAgainstDealer(dealer:Dealer, upCard:BlackjackCard) -> Hand { | |
while hand.value < upCard.rank.values.first + 10 { | |
dealer.dealACardToParticipant(participant: self) | |
} | |
return hand | |
} | |
} | |
//Mark - tests | |
var testHand = Hand() | |
let fiveOfSpades = BlackjackCard(rank: .five, suit: .spades) | |
let fourOfHearts = BlackjackCard(rank: .four, suit: .hearts) | |
testHand.cards.append(contentsOf: [fiveOfSpades, fourOfHearts]) | |
assert(testHand.value == 9) | |
let aceOfHearts = BlackjackCard(rank: .ace, suit: .hearts) | |
testHand.cards.append(aceOfHearts) | |
assert(testHand.value == 20) | |
testHand = Hand() | |
testHand.cards.append(contentsOf: [fiveOfSpades, fourOfHearts, fourOfHearts]) | |
assert(testHand.value == 13) | |
testHand.cards.append(aceOfHearts) | |
assert(testHand.value == 14) | |
//Mark - play | |
let dealer = Dealer() | |
let player1 = Player() | |
let player2 = Player() | |
dealer.dealInitialHandsToParticipants(participants: [dealer, player1, player2]) | |
if let upCard = dealer.upCard { | |
print("|**** Initial Hands ****|") | |
print("Dealer Hand: [ ?? of ??] \(upCard.description)") | |
print("Player 1 Hand: \(player1.hand.description)") | |
print("Player 2 Hand: \(player2.hand.description)") | |
player1.playAgainstDealer(dealer: dealer, upCard: upCard) | |
player2.playAgainstDealer(dealer: dealer, upCard: upCard) | |
dealer.dealToFinish() | |
print("\n|**** Final Hands ****|") | |
print("Dealer Hand: \(dealer.hand.description)") | |
print("Player 1 Hand: \(player1.hand.description)") | |
print("Player 2 Hand: \(player2.hand.description)") | |
print("\n|**** Result ****|") | |
print("Player 1 \(dealer.beat(player: player1) ? "Loses" : "Wins")") | |
print("Player 2 \(dealer.beat(player: player2) ? "Loses" : "Wins")") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment