二十一点牌的总价值
Total value of cards in blackjack
我正在编写一个 21 点纸牌游戏,试图慢慢让自己回到 Swift。
我正在尝试获取玩家手牌的总价值。
我遇到的问题是,当我得到一个可以是 1 或 11 的 ace 时,我不确定在针对它进行 XCTest 时如何解决这个问题。
// Card model
struct Card {
// Suit enumerated
enum Suit : Character {
case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
}
// Rank enumerated
enum Rank : Int {
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)
}
}
}
let rank: Rank, suit : Suit
var value : Rank.Values {
return self.rank.values
}
}
等我来测试的时候,
// XCTest
func testSumOfCardsEquals21() {
let card1 = Card(rank: .jack, suit: .diamonds) //10
let card2 = Card(rank: .four, suit: .diamonds) //4
let card3 = Card(rank: .three, suit: .diamonds) //3
let card4 = Card(rank: .ace, suit: .diamonds) //1 or 11
let hand = [card1, card2, card3, card4]
var total = 0
for card in hand {
let values = card.value
if (values.second == nil) {
total += values.first
} else {
let secondValue = values.second!
total += secondValue
}
}
// expected 21
XCTAssertEqual(total, 21) // this will fail and return 28
}
在这种情况下,您希望 A 低。
在您可能只有一张牌(A)的情况下,您希望它高。
我不知道如何解决这样的测试要求。
...
澄清一下,你如何做一个函数,测试计算手牌的总价值return当一张牌可以是两个价值时,预期的总数是21?
感谢您的帮助和时间。
那手牌是 18,而不是 21。
Values
类型可能没有用——这些卡片实际上没有原始值。
不先把所有的牌都累积起来,就不知道怎么计算得分了。
enum Rank: CaseIterable {
case two, three, four, five, six, seven, eight, nine, ten
case jack, queen, king
case ace
}
struct Hand {
init<Cards: Sequence>(cards: Cards) where Cards.Element == Card {
let reduction = cards.reduce(into: (score: 0, aceCount: 0)) {
switch .rank {
case .jack, .queen, .king:
[=11=].score += 10
case .ace:
[=11=].score += 1
[=11=].aceCount += 1
default:
[=11=].score += try! .rank.caseIndex + 2
}
}
var score = reduction.score
reduction.aceCount.iterations
.prefix { score <= 12 }
.forEach { score += 9 }
self.score = score
}
let score: Int
}
Hand(cards: [card1, card2, card3, card4]).score
public extension ExpressibleByIntegerLiteral where Self: Strideable, Stride: SignedInteger {
/// *This many* iterations that produce no values.
var iterations: LazyMapSequence<Range<Self>, Void> {
(0..<self).lazy.map { _ in }
}
}
public extension CaseIterable where Self: Equatable {
/// The first match for this case in `allCases`.
/// - Throws: `AllCasesError<Self>.noIndex`
var caseIndex: AllCases.Index {
get throws {
do { return try Self.allCases.firstIndex(of: self).unwrapped }
catch { throw AllCasesError.noIndex(self) }
}
}
}
public enum AllCasesError<Case: CaseIterable>: Error {
/// No `AllCases.Index` corresponds to this case.
case noIndex(Case)
}
public extension Optional {
/// Represents that an `Optional` was `nil`.
enum UnwrapError: Error {
case `nil`
case typeMismatch
}
/// [An alterative to overloading `??` to throw errors upon `nil`.](
/// https://forums.swift.org/t/unwrap-or-throw-make-the-safe-choice-easier/14453/7)
/// - Note: Useful for emulating `break`, with `map`, `forEach`, etc.
/// - Throws: `UnwrapError` when `nil`.
var unwrapped: Wrapped {
get throws {
switch self {
case let wrapped?:
return wrapped
case nil:
throw UnwrapError.nil
}
}
}
}
我正在编写一个 21 点纸牌游戏,试图慢慢让自己回到 Swift。
我正在尝试获取玩家手牌的总价值。
我遇到的问题是,当我得到一个可以是 1 或 11 的 ace 时,我不确定在针对它进行 XCTest 时如何解决这个问题。
// Card model
struct Card {
// Suit enumerated
enum Suit : Character {
case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
}
// Rank enumerated
enum Rank : Int {
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)
}
}
}
let rank: Rank, suit : Suit
var value : Rank.Values {
return self.rank.values
}
}
等我来测试的时候,
// XCTest
func testSumOfCardsEquals21() {
let card1 = Card(rank: .jack, suit: .diamonds) //10
let card2 = Card(rank: .four, suit: .diamonds) //4
let card3 = Card(rank: .three, suit: .diamonds) //3
let card4 = Card(rank: .ace, suit: .diamonds) //1 or 11
let hand = [card1, card2, card3, card4]
var total = 0
for card in hand {
let values = card.value
if (values.second == nil) {
total += values.first
} else {
let secondValue = values.second!
total += secondValue
}
}
// expected 21
XCTAssertEqual(total, 21) // this will fail and return 28
}
在这种情况下,您希望 A 低。
在您可能只有一张牌(A)的情况下,您希望它高。
我不知道如何解决这样的测试要求。
...
澄清一下,你如何做一个函数,测试计算手牌的总价值return当一张牌可以是两个价值时,预期的总数是21?
感谢您的帮助和时间。
那手牌是 18,而不是 21。
Values
类型可能没有用——这些卡片实际上没有原始值。
不先把所有的牌都累积起来,就不知道怎么计算得分了。
enum Rank: CaseIterable {
case two, three, four, five, six, seven, eight, nine, ten
case jack, queen, king
case ace
}
struct Hand {
init<Cards: Sequence>(cards: Cards) where Cards.Element == Card {
let reduction = cards.reduce(into: (score: 0, aceCount: 0)) {
switch .rank {
case .jack, .queen, .king:
[=11=].score += 10
case .ace:
[=11=].score += 1
[=11=].aceCount += 1
default:
[=11=].score += try! .rank.caseIndex + 2
}
}
var score = reduction.score
reduction.aceCount.iterations
.prefix { score <= 12 }
.forEach { score += 9 }
self.score = score
}
let score: Int
}
Hand(cards: [card1, card2, card3, card4]).score
public extension ExpressibleByIntegerLiteral where Self: Strideable, Stride: SignedInteger {
/// *This many* iterations that produce no values.
var iterations: LazyMapSequence<Range<Self>, Void> {
(0..<self).lazy.map { _ in }
}
}
public extension CaseIterable where Self: Equatable {
/// The first match for this case in `allCases`.
/// - Throws: `AllCasesError<Self>.noIndex`
var caseIndex: AllCases.Index {
get throws {
do { return try Self.allCases.firstIndex(of: self).unwrapped }
catch { throw AllCasesError.noIndex(self) }
}
}
}
public enum AllCasesError<Case: CaseIterable>: Error {
/// No `AllCases.Index` corresponds to this case.
case noIndex(Case)
}
public extension Optional {
/// Represents that an `Optional` was `nil`.
enum UnwrapError: Error {
case `nil`
case typeMismatch
}
/// [An alterative to overloading `??` to throw errors upon `nil`.](
/// https://forums.swift.org/t/unwrap-or-throw-make-the-safe-choice-easier/14453/7)
/// - Note: Useful for emulating `break`, with `map`, `forEach`, etc.
/// - Throws: `UnwrapError` when `nil`.
var unwrapped: Wrapped {
get throws {
switch self {
case let wrapped?:
return wrapped
case nil:
throw UnwrapError.nil
}
}
}
}