From cc7e569cc9b64e824abbc58de3a0f02d89f1eaf4 Mon Sep 17 00:00:00 2001 From: Ben Scheirman Date: Wed, 21 Dec 2016 16:25:24 -0600 Subject: [PATCH] Episode 248 --- 248-poker-hands-part-1/pokerhands/.gitignore | 4 ++ 248-poker-hands-part-1/pokerhands/Gemfile | 4 ++ .../pokerhands/Gemfile.lock | 51 ++++++++++++++++ 248-poker-hands-part-1/pokerhands/Guardfile | 27 +++++++++ .../pokerhands/Package.swift | 8 +++ .../pokerhands/Sources/Card.swift | 34 +++++++++++ .../pokerhands/Sources/CardValue.swift | 60 +++++++++++++++++++ .../pokerhands/Sources/Parser.swift | 20 +++++++ .../pokerhands/Sources/Player.swift | 4 ++ .../pokerhands/Sources/Suit.swift | 15 +++++ .../pokerhands/Sources/main.swift | 0 .../pokerhands/Sources/pokerhands.swift | 4 ++ .../pokerhandsTests/pokerhandsTests.swift | 48 +++++++++++++++ 13 files changed, 279 insertions(+) create mode 100644 248-poker-hands-part-1/pokerhands/.gitignore create mode 100644 248-poker-hands-part-1/pokerhands/Gemfile create mode 100644 248-poker-hands-part-1/pokerhands/Gemfile.lock create mode 100644 248-poker-hands-part-1/pokerhands/Guardfile create mode 100644 248-poker-hands-part-1/pokerhands/Package.swift create mode 100644 248-poker-hands-part-1/pokerhands/Sources/Card.swift create mode 100644 248-poker-hands-part-1/pokerhands/Sources/CardValue.swift create mode 100644 248-poker-hands-part-1/pokerhands/Sources/Parser.swift create mode 100644 248-poker-hands-part-1/pokerhands/Sources/Player.swift create mode 100644 248-poker-hands-part-1/pokerhands/Sources/Suit.swift create mode 100644 248-poker-hands-part-1/pokerhands/Sources/main.swift create mode 100644 248-poker-hands-part-1/pokerhands/Sources/pokerhands.swift create mode 100644 248-poker-hands-part-1/pokerhands/Tests/pokerhandsTests/pokerhandsTests.swift diff --git a/248-poker-hands-part-1/pokerhands/.gitignore b/248-poker-hands-part-1/pokerhands/.gitignore new file mode 100644 index 0000000..02c0875 --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj diff --git a/248-poker-hands-part-1/pokerhands/Gemfile b/248-poker-hands-part-1/pokerhands/Gemfile new file mode 100644 index 0000000..3a17d64 --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +gem 'guard-shell' +gem 'colored' diff --git a/248-poker-hands-part-1/pokerhands/Gemfile.lock b/248-poker-hands-part-1/pokerhands/Gemfile.lock new file mode 100644 index 0000000..89842e0 --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Gemfile.lock @@ -0,0 +1,51 @@ +GEM + remote: https://rubygems.org/ + specs: + coderay (1.1.1) + colored (1.2) + ffi (1.9.14) + formatador (0.2.5) + guard (2.14.0) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + lumberjack (~> 1.0) + nenv (~> 0.1) + notiffany (~> 0.0) + pry (>= 0.9.12) + shellany (~> 0.0) + thor (>= 0.18.1) + guard-compat (1.2.1) + guard-shell (0.7.1) + guard (>= 2.0.0) + guard-compat (~> 1.0) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + lumberjack (1.0.10) + method_source (0.8.2) + nenv (0.3.0) + notiffany (0.1.1) + nenv (~> 0.1) + shellany (~> 0.0) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + rb-fsevent (0.9.8) + rb-inotify (0.9.7) + ffi (>= 0.5.0) + ruby_dep (1.5.0) + shellany (0.0.1) + slop (3.6.0) + thor (0.19.4) + +PLATFORMS + ruby + +DEPENDENCIES + colored + guard-shell + +BUNDLED WITH + 1.12.5 diff --git a/248-poker-hands-part-1/pokerhands/Guardfile b/248-poker-hands-part-1/pokerhands/Guardfile new file mode 100644 index 0000000..4fd4480 --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Guardfile @@ -0,0 +1,27 @@ +require 'colored' +require 'open3' + +clearing :on + +guard :shell do + watch(/(.*).swift$/) {|m| + output = "" + errors = "" + exit_status = Open3.popen3("swift test") do |stdin, stdout, stderr, wait_thr| + stdin.close + output << stdout.read + errors << stderr.read + wait_thr.value + end + + puts output.yellow + + if exit_status.success? + puts errors.cyan + puts "Passed".green + else + puts errors.red + puts "Failed".red + end + } +end diff --git a/248-poker-hands-part-1/pokerhands/Package.swift b/248-poker-hands-part-1/pokerhands/Package.swift new file mode 100644 index 0000000..fa62c2f --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Package.swift @@ -0,0 +1,8 @@ +import PackageDescription + +let package = Package( + name: "pokerhands", + dependencies: [ + .Package(url: "https://github.com/kylef/Commander.git", majorVersion: 0, minor: 5) + ] +) diff --git a/248-poker-hands-part-1/pokerhands/Sources/Card.swift b/248-poker-hands-part-1/pokerhands/Sources/Card.swift new file mode 100644 index 0000000..086c520 --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Sources/Card.swift @@ -0,0 +1,34 @@ +struct Card: CustomStringConvertible { + let value: CardValue + let suit: Suit + + init?(value: CardValue?, suit: Suit?) { + guard let value = value, let suit = suit else { return nil } + self.value = value + self.suit = suit + } + + static func parse(_ string: String) -> Card? { + guard string.characters.count == 2 else { return nil } + let index = string.index(after: string.startIndex) + let cardValue = CardValue(display: string.substring(to: index)) + let suit = Suit(rawValue: string.substring(from: index)) + return Card(value: cardValue, suit: suit) + } + + var description: String { + return "\(value)\(suit)" + } +} + +extension Card: Equatable { + static func ==(lhs: Card, rhs: Card) -> Bool { + return lhs.value == rhs.value && lhs.suit == rhs.suit + } +} + +extension Card: Comparable { + static func <(lhs: Card, rhs: Card) -> Bool { + return lhs.value < rhs.value + } +} diff --git a/248-poker-hands-part-1/pokerhands/Sources/CardValue.swift b/248-poker-hands-part-1/pokerhands/Sources/CardValue.swift new file mode 100644 index 0000000..c85ee69 --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Sources/CardValue.swift @@ -0,0 +1,60 @@ +struct CardValue: ExpressibleByIntegerLiteral { + let display: String + let value: Int + + init(integerLiteral: Int) { + self.value = integerLiteral + switch value { + case 2..<10: display = String(value) + case 10: display = "T" + case 11: display = "J" + case 12: display = "Q" + case 13: display = "K" + case 14: display = "A" + default: fatalError("value \(integerLiteral) out of bounds for cardValue") + } + } + + init?(display: String) { + guard display.characters.count == 1 else { return nil } + self.display = display + switch display { + case "T": value = 10 + case "J": value = 11 + case "Q": value = 12 + case "K": value = 13 + case "A": value = 14 + default: + if let digit = Int(display) { + value = digit + } else { + return nil + } + } + } + +} + +extension CardValue: Equatable { + static func ==(lhs: CardValue, rhs: CardValue) -> Bool { + return lhs.value == rhs.value + } +} + +extension CardValue: CustomStringConvertible { + var description: String { + return display + } +} + +extension CardValue: Comparable { + static func <(lhs: CardValue, rhs: CardValue) -> Bool { + return lhs.value < rhs.value + } +} + +extension CardValue : Hashable { + var hashValue: Int { + return value + } +} diff --git a/248-poker-hands-part-1/pokerhands/Sources/Parser.swift b/248-poker-hands-part-1/pokerhands/Sources/Parser.swift new file mode 100644 index 0000000..3257c0c --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Sources/Parser.swift @@ -0,0 +1,20 @@ +import Foundation + +class Parser { + let input: String + + init(input: String) { + self.input = input + } + + func parse() -> [Player] { + let parts = input.components(separatedBy: " ") + return parts.map { part in + let playerParts = part.components(separatedBy: ": ") + let name = playerParts[0] + let cardStrings = playerParts[1].components(separatedBy: " ") + let cards = cardStrings.flatMap(Card.parse) + return Player(name: name, cards: cards) + } + } +} diff --git a/248-poker-hands-part-1/pokerhands/Sources/Player.swift b/248-poker-hands-part-1/pokerhands/Sources/Player.swift new file mode 100644 index 0000000..9402106 --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Sources/Player.swift @@ -0,0 +1,4 @@ +struct Player { + let name: String + let cards: [Card] +} diff --git a/248-poker-hands-part-1/pokerhands/Sources/Suit.swift b/248-poker-hands-part-1/pokerhands/Sources/Suit.swift new file mode 100644 index 0000000..843f4e9 --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Sources/Suit.swift @@ -0,0 +1,15 @@ +enum Suit: String, CustomStringConvertible { + case hearts = "H" + case spades = "S" + case diamonds = "D" + case clubs = "C" + + var description: String { + switch self { + case .hearts: return "❤️" + case .spades: return "♠️" + case .diamonds: return "♦️" + case .clubs: return "♣️" + } + } +} diff --git a/248-poker-hands-part-1/pokerhands/Sources/main.swift b/248-poker-hands-part-1/pokerhands/Sources/main.swift new file mode 100644 index 0000000..e69de29 diff --git a/248-poker-hands-part-1/pokerhands/Sources/pokerhands.swift b/248-poker-hands-part-1/pokerhands/Sources/pokerhands.swift new file mode 100644 index 0000000..caa086e --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Sources/pokerhands.swift @@ -0,0 +1,4 @@ +struct pokerhands { + + var text = "Hello, World!" +} diff --git a/248-poker-hands-part-1/pokerhands/Tests/pokerhandsTests/pokerhandsTests.swift b/248-poker-hands-part-1/pokerhands/Tests/pokerhandsTests/pokerhandsTests.swift new file mode 100644 index 0000000..0451b55 --- /dev/null +++ b/248-poker-hands-part-1/pokerhands/Tests/pokerhandsTests/pokerhandsTests.swift @@ -0,0 +1,48 @@ +import XCTest +@testable import pokerhands + +class pokerhandsTests: XCTestCase { + let input = "Black: 2H 3D 5S 9C KD White: 2C 3H 4S 8C AH" + + func testParsesPlayers() { + let parser = Parser(input: input) + let players = parser.parse() + XCTAssertEqual(2, players.count) + XCTAssertEqual(["Black", "White"], players.map { $0.name }) + } + + func testParsesPlayerHands() { + let parser = Parser(input: input) + let players = parser.parse() + let cards = players[0].cards + XCTAssertEqual(5, cards.count) + let expectedCards = [ + Card.parse("2H"), + Card.parse("3D"), + Card.parse("5S"), + Card.parse("9C"), + Card.parse("KD"), + ].flatMap { $0 } + XCTAssertEqual(expectedCards, cards) + } + + func testParsesCards() { + let cardString = "5H" + let card = Card.parse(cardString) + XCTAssertEqual(5, card?.value) + XCTAssertEqual(Suit.hearts, card?.suit) + } + + func testDetectsHighCard() { + let expectedHighCard = Card.parse("KD") + let hand = [ + Card.parse("2H"), + Card.parse("3D"), + Card.parse("5S"), + Card.parse("9C"), + Card.parse("KD"), + ].flatMap { $0 } + + XCTAssertEqual(expectedHighCard, hand.max()) + } +}