Help us understand the problem. What is going on with this article?

ブラックジャックをGoで実装してみた。

More than 1 year has passed since last update.

プログラミング入門者からの卒業試験は『ブラックジャック』を開発すべし」という気合の入った記事が投稿されていたので実際にやってみた。

元記事ではC#を使うことを想定していたようだが、普段使っているGoを選択した。

ソースコード

github.com/aimof/blackjack

ぱっとやってみた感じそれっぽく動いています。

元記事内縦長のかわいいAA以降は読んでいません(より正確に言うならルールすらちゃんと読んでなかった)。
2〜3時間のやっつけ仕事でテストも最低限なので、ちょっと見せびらかすには物足りない…。

ポイント

指摘されていたポイントを詰めていきます。

カードの管理

0~51の整数で管理しました。

type card struct {
    id int
}

func (c card) suit() string {
    switch c.id % 4 {
    case 0:
        return "C"
    case 1:
        return "D"
    case 2:
        return "H"
    default:
        return "S"
    }
}

// Aの場合1を返す
func (c card) strength() int {
    if c.id >= 40 {
        return 10
    } else {
        return c.id/4 + 1
    }
}

func (c card) number() string {
    switch c.id / 4 {
    case 0:
        return "A"
    case 9:
        return "T"
    case 10:
        return "J"
    case 11:
        return "Q"
    case 12:
        return "K"
    default:
        return strconv.Itoa(c.id/4 + 1)
    }
}

func (c card) toString() string {
    var s string
    s += c.suit()
    s += c.number()
}

それぞれ、

  • suitメソッド:スート(CDHS)を返す
  • strengthメソッド:強さ(Aのときは1)を返す
  • numberメソッド:気持ちの悪い名前をしているが、表示用のカード名を返す(ATJQKはアルファベット)
  • toStringメソッド:スートとランクをくっつけた文字列を返す

山札について

type deck struct {
    // if true, the card is drawn.
    cards [52]bool
}

func newDeck() *deck {
    return &deck{}
}

func (d *deck) draw() int {
    var drawnN int
    for {
        n := rand.Intn(52)
        if d.cards[n] {
            continue
        } else {
            d.cards[n] = true
            drawnN = n
            break
        }
    }
    return drawnN
}

こんな感じで配列での実装です。
カードドローの実装は、デッキにないものをひこうとした場合には再抽選という原始的な方法。
ここは実装を変えたい。

ちなみに、デックはグローバル変数にしてある。
この規模ならわかりやすいかと思ったが果たしてどうなのだろうか?

Aは1か11か問題

type cards []card

func (c cards) reveal() (sumExceptAce, countAce int) {
    for _, card := range c {
        if card.strength() == 1 {
            countAce++
        } else {
            sumExceptAce += card.strength()
        }
    }
    return sumExceptAce, countAce
}

func (c cards) strength() int {
    var sum = 0
    sumExceptAce, countAce := c.reveal()
    switch countAce {
    case 0:
        sum = sumExceptAce
    case 1:
        if sumExceptAce <= 10 {
            sum = sumExceptAce + 11
        } else {
            sum = sumExceptAce + 1
        }
    default:
        if sumExceptAce+countAce > 11 {
            sum = sumExceptAce + countAce
        } else {
            sum = sumExceptAce + countAce + 10
        }
    }
    if sum > 21 {
        return 0
    }
    return sum
}

ちょっと複雑になってしまいました。エース以外の和とエースの枚数で計算しています。

playerとdealerの実装について

type dealer struct {
    cards cards
}

func (d *dealer) play() {
    for d.cards.strength() < 17 && d.cards.strength() > 0 {
        d.cards = append(d.cards, card{id: usedDeck.draw()})
    }
}

type player struct {
    cards cards
}

func (p *player) play() {
    p.cards = append(p.cards, card{id: usedDeck.draw()})
}

元記事ではいろいろと議論が起こっているようだが、プレイヤーは手札を持ってプレイだけしていればいいと思う。

まとめ

結構楽しかった。工夫のしどころが結構多かったです。

ご意見お待ちしています。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away