Last active
August 28, 2017 11:28
-
-
Save DarinM223/36ebb36d6862a016955ba546bc005fde to your computer and use it in GitHub Desktop.
Simple Swift program to learn Swift 3
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
| // Simple Blackjack game in Swift 3 | |
| import Foundation | |
| // Extension to allow for shuffling of arrays | |
| extension MutableCollection where Index == Int { | |
| mutating func shuffle() { | |
| if count < 2 { | |
| return | |
| } | |
| for i in startIndex..<endIndex - 1 { | |
| let j = Int(arc4random_uniform(UInt32(endIndex - i))) + i | |
| guard i != j else { continue } | |
| swap(&self[i], &self[j]) | |
| } | |
| } | |
| } | |
| enum Suite { | |
| case Hearts | |
| case Spades | |
| case Clubs | |
| case Diamonds | |
| } | |
| enum Action { | |
| case Stand | |
| case Hit | |
| } | |
| struct Card { | |
| let suite: Suite | |
| let value: Int | |
| let visible: Bool | |
| } | |
| class Deck { | |
| private var cards: [Card] = [] | |
| private func addSuiteCards(suite: Suite) { | |
| for i in 1...13 { | |
| cards.append(Card(suite: suite, value: i, visible: true)) | |
| } | |
| } | |
| init() { | |
| addSuiteCards(suite: .Hearts) | |
| addSuiteCards(suite: .Spades) | |
| addSuiteCards(suite: .Clubs) | |
| addSuiteCards(suite: .Diamonds) | |
| shuffle() | |
| } | |
| func drawHiddenCard() -> Optional<Card> { | |
| return cards.popLast().map({ (card: Card) -> Card in | |
| return Card(suite: card.suite, value: card.value, visible: false) | |
| }) | |
| } | |
| func drawCard() -> Optional<Card> { | |
| return cards.popLast() | |
| } | |
| func shuffle() { | |
| cards.shuffle() | |
| } | |
| func empty() -> Bool { | |
| return cards.isEmpty | |
| } | |
| func size() -> Int { | |
| return cards.count | |
| } | |
| } | |
| protocol Playable { | |
| func score() -> Int | |
| func decideAction() -> Action | |
| func addCard(card: Card) | |
| } | |
| class Player: Playable { | |
| private var numHighAces: Int | |
| private var myScore: Int | |
| private var money: Int | |
| init(initialMoney: Int) { | |
| money = initialMoney | |
| numHighAces = 0 | |
| myScore = 0 | |
| } | |
| func score() -> Int { | |
| return myScore | |
| } | |
| func decideAction() -> Action { | |
| while true { | |
| print("Enter (1) to Hit, (2) to Stand") | |
| if let x = Int(readLine()!) { | |
| if x == 1 { | |
| return .Hit | |
| } else if x == 2 { | |
| return .Stand | |
| } | |
| } | |
| } | |
| } | |
| func addCard(card: Card) { | |
| var value: Int = 0 | |
| if card.value == 1 { | |
| numHighAces += 1 | |
| value = 11 | |
| } else { | |
| value = card.value | |
| } | |
| (myScore, numHighAces) = addScore(previousScore: myScore, value: value, numHighAces: numHighAces) | |
| } | |
| func placeBet(amount: Int) -> Optional<Int> { | |
| if money - amount >= 0 { | |
| return .some(amount) | |
| } | |
| return .none | |
| } | |
| func totalMoney() -> Int { | |
| return money | |
| } | |
| func takeMoney(amount: Int) { | |
| if money - amount >= 0 { | |
| money -= amount | |
| } else { | |
| money = 0 | |
| } | |
| } | |
| func addMoney(amount: Int) { | |
| money += amount | |
| } | |
| } | |
| class Dealer: Playable { | |
| private var numHighAces: Int | |
| private var myScore: Int | |
| init() { | |
| numHighAces = 0 | |
| myScore = 0 | |
| } | |
| func score() -> Int { | |
| return myScore | |
| } | |
| func decideAction() -> Action { | |
| if score() >= 17 { | |
| return .Stand | |
| } | |
| return .Hit | |
| } | |
| // NOTE(DarinM223): implementation identical to Player's addCard method. Maybe refactor into common function? | |
| func addCard(card: Card) { | |
| var value: Int = 0 | |
| if card.value == 1 { | |
| numHighAces += 1 | |
| value = 11 | |
| } else { | |
| value = card.value | |
| } | |
| (myScore, numHighAces) = addScore(previousScore: myScore, value: value, numHighAces: numHighAces) | |
| } | |
| } | |
| class BlackjackGame { | |
| private var dealer: Dealer = Dealer() | |
| private var players: [Player] | |
| private var bets: Dictionary<Int, Int> = [:] | |
| private var deck: Deck = Deck() | |
| init(players initPlayers: [Player]) { | |
| players = initPlayers | |
| } | |
| func applyAction(playable: Playable, action: Action) { | |
| if action == .Hit { | |
| deck.drawCard().map({ (card: Card) -> Void in playable.addCard(card: card) }) | |
| } | |
| } | |
| // Deals two cards to a player or a dealer. | |
| func deal(playable: Playable) { | |
| deck.drawCard().map({ (card: Card) -> Void in playable.addCard(card: card) }) | |
| deck.drawCard().map({ (card: Card) -> Void in playable.addCard(card: card) }) | |
| } | |
| func placeBet(playerIndex: Int, player: Player) { | |
| while true { | |
| print("Enter the bet amount for player: ", playerIndex + 1) | |
| let amount = Int(readLine()!)! | |
| if case .some(_) = player.placeBet(amount: amount) { | |
| bets.updateValue(amount, forKey: playerIndex) | |
| return | |
| } | |
| print("Bet amount too large") | |
| } | |
| } | |
| func calculateBets() { | |
| if dealer.score() > 21 { | |
| print("Dealer busted") | |
| for (i, player) in players.enumerated() { | |
| if player.score() <= 21 { | |
| print("Player ", i + 1, " won") | |
| player.addMoney(amount: bets[i]!) | |
| print("Player received: ", bets[i]!) | |
| } else { | |
| print("Player ", i + 1, " busted") | |
| player.takeMoney(amount: bets[i]!) | |
| print("Player lost: ", bets[i]!) | |
| } | |
| } | |
| } else { | |
| for (i, player) in players.enumerated() { | |
| if player.score() < dealer.score() { | |
| print("Player ", i + 1, "won") | |
| player.addMoney(amount: bets[i]!) | |
| print("Player received: ", bets[i]!) | |
| } else if player.score() > dealer.score() { | |
| print("Player ", i + 1, "lost") | |
| player.takeMoney(amount: bets[i]!) | |
| print("Player lost: ", bets[i]!) | |
| } else { | |
| print("Player ", i + 1, " had same score as dealer, no money lost or gained") | |
| } | |
| } | |
| } | |
| } | |
| func run() { | |
| for i in 0..<players.count { | |
| placeBet(playerIndex: i, player: players[i]) | |
| } | |
| for player in players { | |
| deal(playable: player) | |
| } | |
| deal(playable: dealer) | |
| for (i, player) in players.enumerated() { | |
| print("Player ", i + 1, "'s score: ", player.score()) | |
| let action = player.decideAction() | |
| applyAction(playable: player, action: action) | |
| } | |
| let action = dealer.decideAction() | |
| applyAction(playable: dealer, action: action) | |
| calculateBets() | |
| } | |
| } | |
| func addScore(previousScore prevScore: Int, value: Int, numHighAces numAces: Int) -> (Int, Int) { | |
| var newScore = prevScore + value | |
| var numHighAces = numAces | |
| while newScore > 21 && numAces > 0 { | |
| numHighAces -= 1 | |
| newScore -= 10 | |
| } | |
| return (newScore, numHighAces) | |
| } | |
| let numPlayers = 3 | |
| let initialMoney = 100 | |
| let players = (0..<numPlayers).map({ (_: Int) -> Player in Player(initialMoney: initialMoney) }) | |
| let game = BlackjackGame(players: players) | |
| game.run() | |
| for (i, player) in players.enumerated() { | |
| print("Player ", i + 1, "'s money is: ", player.totalMoney()) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment