Skip to content

Instantly share code, notes, and snippets.

@DarinM223
Last active August 28, 2017 11:28
Show Gist options
  • Save DarinM223/36ebb36d6862a016955ba546bc005fde to your computer and use it in GitHub Desktop.
Save DarinM223/36ebb36d6862a016955ba546bc005fde to your computer and use it in GitHub Desktop.
Simple Swift program to learn Swift 3
// 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